93

I need to create a solid color inset border. This is the bit of CSS I'm using:

border: 10px inset rgba(51,153,0,0.65);

Unfortunately that creates a 3D ridged border (ignore the squares and dark description box)

Simon Arnold
  • 15,849
  • 7
  • 67
  • 85
JacobTheDev
  • 17,318
  • 25
  • 95
  • 158
  • 4
    Border as defined in CSS is always added to the outside of the box, it will never collapse into the box and overlap content behind it. You'd have to add another box on top of it. – animuson Dec 09 '11 at 23:00
  • 4
    Image links are dead... – Matthieu Jan 21 '20 at 14:56

13 Answers13

185

You could use box-shadow, possibly:

#something {
    background: transparent url(https://i.stack.imgur.com/RL5UH.png) 50% 50% no-repeat;
    min-width: 300px;
    min-height: 300px;
    box-shadow: inset 0 0 10px #0f0;
}

#something {
  background: transparent url(https://i.stack.imgur.com/RL5UH.png) 50% 50% no-repeat;
  min-width: 300px;
  min-height: 300px;
  box-shadow: inset 0 0 10px #0f0;
}
<div id="something"></div>

This has the advantage that it will overlay the background-image of the div, but it is, of course, blurred (as you'd expect from the box-shadow property). To build up the density of the shadow you can add additional shadows of course:

#something {
    background: transparent url(https://i.stack.imgur.com/RL5UH.png) 50% 50% no-repeat;
    min-width: 300px;
    min-height: 300px;
    box-shadow: inset 0 0 20px #0f0, inset 0 0 20px #0f0, inset 0 0 20px #0f0;
}

#something {
  background: transparent url(https://i.stack.imgur.com/RL5UH.png) 50% 50% no-repeat;
  min-width: 300px;
  min-height: 300px;
  box-shadow: inset 0 0 20px #0f0, inset 0 0 20px #0f0, inset 0 0 20px #0f0;
}
<div id="something"></div>

Edited because I realised that I'm an idiot, and forgot to offer the simplest solution first, which is using an otherwise-empty child element to apply the borders over the background:

#something {
  background: transparent url(https://i.stack.imgur.com/RL5UH.png) 50% 50% no-repeat;
  min-width: 300px;
  min-height: 300px;
  padding: 0;
  position: relative;
}
#something div {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  border: 10px solid rgba(0, 255, 0, 0.6);
}
<div id="something">
  <div></div>
</div>

Edited after @CoryDanielson's comment, below:

jsfiddle.net/dPcDu/2 you can add a 4th px parameter for the box-shadow that does the spread and will more easily reflect his images.

#something {
  background: transparent url(https://i.stack.imgur.com/RL5UH.png) 50% 50% no-repeat;
  min-width: 300px;
  min-height: 300px;
  box-shadow: inset 0 0 0 10px rgba(0, 255, 0, 0.5);
}
<div id="something"></div>
Edric
  • 24,639
  • 13
  • 81
  • 91
David Thomas
  • 249,100
  • 51
  • 377
  • 410
  • 12
    http://jsfiddle.net/dPcDu/2/ you can add a 4th px parameter for the box-shadow that does the spread and will more easily reflect his images – Cory Danielson Dec 09 '11 at 23:16
  • 1
    @CoryDanielson: *oooooooh..!* I'd never realised that there was a fourth (presumably) 'width (but not blurred...)' option to the `text-shadow` property! *Awesome!* =) **edited in**, with thanks. – David Thomas Dec 09 '11 at 23:18
  • 2
    yeah a few of the tutorials on box-shadow do a terrible job documenting it... most of the 'coverage' on box-shadow is very inconsistent and poor... it got too popular for it's own good... before I learned about the 4th spread parameter, I would do 10 1px shadows... it was terrible. box-shadow and text-shadow should be more consistent... bleh. `x,y,blur,spread` – Cory Danielson Dec 09 '11 at 23:23
  • 1
    your empty div example is good stuff, i didn't know you could specify top, left, right, bottom all to 0 and it would work like that.. soooo stealing it... ugh, it doesn't work in ie :[ damn ie. – Cory Danielson Dec 09 '11 at 23:23
  • Less a *steal*, more an *exchange*? Gotta love a barter-economy..! Now, who to get my milk from..? =b – David Thomas Dec 09 '11 at 23:25
  • Just a note: `transparent` is needed on `background` for this to work. – ThinkingStiff Dec 10 '11 at 00:53
  • 1
    @CoryDanielson: the `position: absolute;` with all-zeroes works fine in IE, what didn't work was the `background-color` (IE doesn't understand the `rgba()` notation): see [the latest Fiddle](http://jsfiddle.net/davidThomas/dPcDu/5/)! – David Thomas Dec 10 '11 at 20:08
  • I would suggest using a :before element -- much simpler, more widely supported, and no blur or whatever to worry about (and you can do dashed lines, etc.). – podperson Feb 19 '13 at 16:12
  • 1
    +1 for "because I realised that I'm an idiot" ;) and more seriously: +1 for including approaches to the problem and explaining their pros&cons – ioleo Aug 14 '13 at 18:03
  • I know this is a old question, but i want to add that this solution is no longer needed, a better solution would be to add box-sizing: border-box; to the element, this makes all borders inset. But care as it will also affect padding! – Slugge Nov 21 '14 at 12:49
  • the Third option using the Div just needs a few adjustments for a perfect border: parent must have a position property (ie: position: relative) and the width and height of the child element making the border should use a calc() that removes double the width / height of the border (both sides) from the div width to make an inset border. ie: div.child { width: calc(100% - 20px); border: 10px solid blue; } – Eolis Sep 09 '15 at 18:44
  • Not being jealous on your many upvotes but I literally answered the technically exactly same and that 4 years before you did. Sometimes SO confuses me a little... – Chris S. Sep 12 '18 at 08:54
  • 1
    @ChrisS.: this answer was originally submitted 2011-12-09 (though the most recent edit, by the Community user, was 2017-05-23); your answer - the first revision - so far as I can tell was submitted 2013-05-21. So, no: your answer came eighteen months after my own rather than "*4 years before.*" – David Thomas Sep 12 '18 at 09:38
  • Thanks for clarifying. But as I said I'm not being jealous. I was just confused. – Chris S. Sep 12 '18 at 09:53
  • @David says reinstate Monica: Made use of only: box-shadow: inset 1px 0px 1px #000; Love you bro, you just pulled me out of my misery, had been struggling with variations of border and box-shadow for some time now for my special case. – Uzair Khan May 05 '20 at 09:27
40

I would recomnend using box-sizing.

*{
  -webkit-box-sizing:border-box;
  -moz-box-sizing:border-box;
  -ms-box-sizing:border-box;
  box-sizing:border-box;
}

#bar{
  border: 10px solid green;
  }
26

To produce a border inset within an element the only solution I've found (and I've tried all the suggestions in this thread to no avail) is to use a pseudo-element such as :before

E.g.

.has-inset-border:before {
  content: " "; /* to ensure it displays */
  position: absolute;
  left: 10px;
  right: 10px;
  top: 10px;
  bottom: 10px;
  border: 4px dashed red;
  pointer-events: none; /* user can't click on it */
}

The box-sizing property won't work, as the border always ends up outside everything.

The box-shadow options has the dual disadvantages of not really working and not being supported as widely (and costing more CPU cycles to render, if you care).

podperson
  • 2,284
  • 2
  • 24
  • 24
  • 1
    This works well on spans and such ; I saw that Facebook uses this technique too. Beware that in most browsers, :before and :after do not work on IMG elements though. – Louis Ameline Sep 13 '14 at 10:16
  • Just wanted to say nice job :) – Wes Duff Aug 18 '15 at 14:40
  • @Evan: good point (and img tags not having pseudo elements is one of those zillion gotchas) – podperson Aug 19 '15 at 06:39
  • 1
    Great solution - worked very well. This should be higher up the page! – Liran H Dec 11 '15 at 14:00
  • Thanks! Easily the best solution to this problem! – clayRay Jun 14 '19 at 04:59
  • BTW elements not having pseudo elements is a general property of self-closed tags: https://stackoverflow.com/questions/3538506/which-elements-support-the-before-and-after-pseudo-elements – podperson Mar 26 '21 at 15:37
  • I should add that these days with box-shadow widely supported, I pretty much only use box-shadow to generate borders, but this technique works just as well with box-shadow. – podperson Jun 02 '23 at 18:59
17

It's an old trick, but I still find the easiest way to do this is to use outline-offset with a negative value (example below uses -6px). Here's a fiddle of it—I've made the outer border red and the outline white to differentiate the two:

.outline-offset {
width:300px;
height:200px;
background:#333c4b;
border:2px solid red;
outline:2px #fff solid;
outline-offset:-6px;
}

<div class="outline-offset"></div>
Vanessa King
  • 181
  • 2
  • 6
  • 1
    It does, it just doesn't add a curve to the inset outline (see updated fiddle http://jsfiddle.net/vf2daLqe/4/). It's easy to use in a lot of situations, but if you want something more complex, another way is going to be better—thanks for pointing that out Ben! – Vanessa King Mar 17 '20 at 19:27
7

If you want to make sure the border is on the inside of your element, you can use

box-sizing:border-box;

this will place the following border on the inside of the element:

border: 10px solid black;

(similar result you'd get using the additonal parameter inset on box-shadow, but instead this one is for the real border and you can still use your shadow for something else.)

Note to another answer above: as soon as you use any inset on box-shadow of a certain element, you are limited to a maximum of 2 box-shadows on that element and would require a wrapper div for further shadowing.

Both solutions should as well get you rid of the undesired 3D effects. Also note both solutions are stackable (see the example I've added in 2018)

.example-border {
  width:100px;
  height:100px;
  border:40px solid blue;
  box-sizing:border-box;
  float:left;
}

.example-shadow {
  width:100px;
  height:100px;
  float:left;
  margin-left:20px;
  box-shadow:0 0 0 40px green inset;
}

.example-combined {
  width:100px;
  height:100px;
  float:left;
  margin-left:20px;
  border:20px solid orange;
  box-sizing:border-box;
  box-shadow:0 0 0 20px red inset;
}
<div class="example-border"></div>
<div class="example-shadow"></div>
<div class="example-combined"></div>
Chris S.
  • 1,199
  • 11
  • 25
4

I don't know what you are comparing to.

But a super simple way to have a border look inset when compared to other non-bordered items is to add a border: ?px solid transparent; to whatever items do not have a border.

It will make the bordered item look inset.

http://jsfiddle.net/cmunns/cgrtd/

Stephan
  • 41,764
  • 65
  • 238
  • 329
Adam Munns
  • 71
  • 4
1

Simple SCSS solution with pseudo-elements

Live demo: https://codepen.io/vlasterx/pen/xaMgag

// Change border size here
$border-width: 5px;

.element-with-border {
 display: flex;
 height: 100px;
 width: 100%;
 position: relative;
 background-color: #f2f2f2;
 box-sizing: border-box;
 
 // Use pseudo-element to create inset border
 &:before {
  position: absolute;
  content: ' ';
  display: flex;
  border: $border-width solid black;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  border: $border-width solid black;
  // Important: We must deduct border size from width and height
  width: calc(100% - $border-width); 
  height: calc(100% - $border-width);
 }
}
<div class="element-with-border">
  Lorem ipsum dolor sit amet
</div>
Vladimir Jovanović
  • 3,288
  • 1
  • 20
  • 27
1

You can do this:

.thing {
  border: 2px solid transparent;
}
.thing:hover {
  border: 2px solid green;
}
0

If box-sizing is not an option, another way to do this is just to make it a child of the sized element.

Demo

CSS

.box {
  width: 100px;
  height: 100px;
  display: inline-block;
  margin-right: 5px;
}
.border {
  border: 1px solid;
  display: block;
}
.medium { border-width: 10px; }
.large  { border-width: 25px; }


HTML

<div class="box">
  <div class="border small">A</div>
</div>
<div class="box">
  <div class="border medium">B</div>
</div>
<div class="box">
  <div class="border large">C</div>
</div>
Adam Grant
  • 12,477
  • 10
  • 58
  • 65
0

I know this is three years old, but thought it might be helpful to someone.

The concept is to use the :after (or :before) selector to position a border within the parent element.

    .container{
        position:relative; /*Position must be set to something*/
    }

    .container:after{
        position:relative;
        top: 0;
        content:"";
        left:0;
        height: 100%; /*Set pixel height and width if not defined in parent element*/
        width: 100%; 

        -webkit-box-sizing:border-box;
        -moz-box-sizing:border-box;
        -ms-box-sizing:border-box;
        box-sizing:border-box;

        border:1px solid #000; /*set your border style*/

    }
Rick
  • 21
  • I don't understand why this answer has negative points, this is a perfectly valid solution, although you don't need the position relative, not top and left properties in the pseudo-element, but this is still a perfectly valid solution – Miguel Sánchez Villafán Nov 29 '20 at 20:17
0

You may use background-clip: border-box;

Example:

.example {
padding: 2em;
border: 10px solid rgba(51,153,0,0.65);
background-clip: border-box;
background-color: yellow;
}

<div class="example">Example with background-clip: border-box;</div>
0

So I was trying to have a border appear on hover but it moved the entire bottom bar of the main menu which didn't look all that good I fixed it with the following:

#top-menu .menu-item a:hover {
    border-bottom:4px solid #ec1c24;
    padding-bottom:14px !important;
}
#top-menu .menu-item a {
    padding-bottom:18px !important;
}

I hope this will help someone out there.

0

Simpler + better | img tag | z-index | link image | "alt" attribute

I figured out a method where you do not need to use the image as a background image but use the img HTML tag inside the div, and using z-index of the div as a negative value.

Advantages:

  • The image can now become a link to a lightbox or to another page
  • The img:hover style can now change image itself, for example: black/white to color, low to high opacity, and much more.
  • Animations of image are possible The image is more accessible because of the alt tag you can use.
  • For SEO the alt tag is important for keywords

#borders {
  margin: 10px auto;
  width: 300px;
  height: 300px;
  position:relative;
    box-shadow: inset 0 0 0 10px rgba(0, 255, 0, 0.5);
}
img {
  position:absolute;
  top:0;
  bottom:0;
  left:0;
  right: 0;
  z-index: -1;
}
<div id="borders">
  <img src="https://i.stack.imgur.com/RL5UH.png">
</div>
Leontine
  • 9
  • 1