[CSS] Inset Box Shadow On Image

I worked on a website where many images should have an inner shadow. To not need to edit all of them in Photoshop, the “inset” value for the CSS3 attribute “box-shadow” came in handy, but it cannot be applied to images without more ado. I want to show my solution here.

CSS box-shadow over img - example
This is how it should look like.

Applied directly on img elements, the shadow stays behind the image, so it is only visible at all if the image has transparency. If you add a wrapper element which gets the shadow, it is still behind the image but can be positioned with z-index. Unfortunately the image has to be moved to the back, moving the wrapper to the front is not possible 1:

1) Wrapper with Box Shadow, Image in The Background

HTML

<div class="box-shadow">
    <img src="/images/graphic.jpg" />
</div>

CSS

.box-shadow {
    box-shadow: 0 0 10px 6px white inset;
}
.box-shadow img {
    position: relative;
    z-index: -1;
}

The problem with this code is that the image is not only placed behind the wrapper but behind all other elements in the same Stacking Context. Which elements form a stacking context is described quite well in the Mozilla Documentation:

  • the root element (HTML),
  • positioned (absolutely or relatively) with a z-index value other than “auto”,
  • a flex item with a z-index value other than “auto”,
  • elements with an opacity value less than 1. (See the specification for opacity),
  • elements with a transform value other than “none”,
  • elements with a mix-blend-mode value other than “normal”,
  • elements with isolation set to “isolate”,
  • on mobile WebKit and Chrome 22+, position: fixed always creates a new stacking context, even when z-index is “auto”
  • specifing any attribute above in will-change even you don’t write themselves directly

2) Stacking Context

In this case it was applicable to assign a z-index and relative positioning to the direct parent element of the wrapper (let’s call it #parent):

CSS

#parent {
    position: relative;
    z-index: 0;
}

If this is not possible, e.g. because it needs a different position value or the z-index has unwanted side effects, I would use opacity instead, with a value of almost 1, so that no effect is visible but it still creates a stacking context.

CSS (alternativ)

#parent {
    opacity: 0.999;
}

Related post on StackOverflow Continue reading “[CSS] Inset Box Shadow On Image”

Notes:

  1. Can anybody explain why? Obviously I still don’t 100% get z-index.

CSS: 3D Ribbon Generator

Inspired by this article on pvmgarage.com I recently created a generator for 3D CSS ribbons and made it available on css3d.net. It creates CSS and HTML code for a cross-browser compatible ribbon effect (not limited to CSS 3!) based on parameters for sizes and colors. The red headers you see in this screenshot are also generated like that:

Have fun with it and feel free to comment if you have any suggestions.

If you are interested in how it works, visit the aforementioned link or read about the CSS Triangle trick at css-tricks.com.

CSS: Pseudo Bold Fonts

Sometimes you want to emphasize text but the bold version of a font is too “big”. With CSS 3 there is a simple way to thicken the regular font.

.pseudo-bold {
  text-shadow: 1px 0 0;
  padding-right: 1px;
  letter-spacing: 1px;
}

It creates a duplication that is shifted 1 pixel to the right, the padding and letter-spacing properties prevent overlapping. Of course such hacks will never look as nice as a real typographic bold font, so there are always other possibilities to consider. A way to make wide bold fonts more unobstrusive is reducing the letter spacing:

.narrow-bold {
  letter-spacing: -1px;
}

Here is a complete example with the Georgia font-family

<style type="text/css">
	#pseudo-bold-example {
		font-family:Georgia; font-size: 24px;
	}
	.bold {
		font-weight: bold;
	}
	.pseudo-bold {
		text-shadow: 1px 0 0;
		padding-right:1px;
		letter-spacing:1px;
	}
	.narrow-bold {
		font-weight: bold;
		letter-spacing:-1px;
	}
	.narrow-pseudo-bold {
		text-shadow: 1px 0 0;
		padding-right:1px;
	}
</style>
<div id="pseudo-bold-example">
	<p>Lorem Ipsum - normal text<br />
	<span class="bold">
		Lorem Ipsum</span> - bold text<br />
	<span class="pseudo-bold">
		Lorem Ipsum</span> - pseudo-bold text</span><br />
	<span class="narrow-bold">
		Lorem Ipsum</span> - narrow bold text<br />
	<span class="narrow-pseudo-bold">
		Lorem Ipsum</span> - narrow pseudo-bold text</span></p>
</div>

This is how it should look like:

pseudo-bold.png

For my current project I eventually decided to go with the narrow bold version, instead of the pseudo bold one. Bonus points: It is fully compatible with CSS 2.

CSS Top margin before out of nowhere

A typical CSS problem but I fall for it again and again. The whole site is shifted down 10-20 pixels in spite of every imaginable variant of margin:0 in the <html> and <body> elements.

So what was it? A <h1> somewhere in the floating layout whose margin-top pushed everything down.

Note to self: Always check for headings!

Useful link: Margin Collapsing