CSS ribbon-like header - css

I'm trying to get a ribbon-like banner effect for a header:
My markup is this:
<header>
<div id="logo">
<img src="">
</div>
</header>
I was thinking I could use pseudo :before and :after elements on the <img>, creating extra white space above and below the image to fake the extended `div:
#logo-wrap img:after {
content: '';
display: inline-block;
position: absolute;
left: 10px;
top: 10px;
width: 100px;
height: 100px;
background-color: #000;
}
And then another :before and :afterpseudo elements for the "shadow-fold".
My problem is: if I end up doing it like this, I'll have to insert another div between #logoand <img> in order to add another pair of :before and :after pseudo elements for the bottom "shadow-fold" and I think I'm having problems using the pseudo elements on the <img> element (nothing is appearing).
Can you shed some light and guide me on the right direction, pls? Perhaps, there is a simple way to just "shrink" the <header>?
EDIT
So, :before and :after can't be used with <img>. Thank you for the info :)
What I would like to know is if there is another way to achieve what I desire instead of wrap-wrap-wrap? :P
i.e: is there a way to make the #logo be bigger than <header> despite being its child and its height being the same (since the <header> has always the same height as the <img>)?
Thanks

I think you're on the right track. I would use borders, but I would make your pseudo-elements be behind the logo like so:
body,html {margin: 0; padding: 0;}
header {
background: #eee;
text-align: center;
margin: 1em 0;
}
#logo {
display: inline-block;
vertical-align: top;
position: relative;
margin: -0.5em 0;
}
#logo:before, #logo:after {
content: '';
position: absolute;
width: 100%;
left: -0.25em;
border: 0 solid transparent;
border-width: 0.5em 0.25em;
color: #aaa; /* set so we only have to have the border color in one place.
if not specified, border color is the same as the text
color. */
}
#logo:before {
border-top: none;
border-bottom-color: initial;
top: 0;
}
#logo:after {
border-bottom: none;
border-top-color: initial;
bottom: 0;
}
#logo img {
position: relative;
display:block;
z-index: 1;
}
<header>
<div id="logo">
<img src="//placehold.it/300x100?text=LOGO"/>
</div>
</header>
The concept is that the pseudo-elements are 100% width of the logo with a little bit extra (determined by the border attributes). Then you use both left and right borders simultaneously. There's a few other tricks in that code that help simplify it, but the general idea is to let your pseudo-elements peek out from behind the logo itself.

Related

CSS: Background color on text doesn't work when the line breaks in responsive mode [duplicate]

This question already has answers here:
Thick underline behind text
(7 answers)
Closed 8 months ago.
I am trying to use a background color on text only, which works fine on single lines, but when the line breaks in responsive mode it ends up looking like this:
Does anyone know what to add to make the yellow background line follow the text on mulitple lines?
This is my code:
.background-highlight {
position: relative;
display: inline-block;
color: #faf9f4;
}
.background-highlight:after {
content: '';
position: absolute;
width: 100%;
height: 10px;
left: 0;
top: 50%;
background-color: #cef230;
z-index: -1;
}
Thanks a lot in advance,
I have used box-decoration-break: clone; property for mainting the same design for multiple lines don't forget to add display: inline; to its child where background is added. in child I have used linear gradient you can generate according to you from here. you can chenge the position of green strip by adjusting gradient values from the site.
.background-highlight {
position: relative;
display: inline-block;
color: #000;
-webkit-box-decoration-break: clone;
box-decoration-break: clone;
font-size: 120px;
}
.background-highlight span {
display: inline;
background: rgb(206,242,48);
background: -webkit-gradient(linear, left bottom, left top, color-stop(11%, rgba(206,242,48,1)), color-stop(12%, rgba(255,255,255,0)));
background: -o-linear-gradient(bottom, rgba(206,242,48,1) 11%, rgba(255,255,255,0) 12%);
background: linear-gradient(0deg, rgba(206,242,48,1) 11%, rgba(255,255,255,0) 12%);
}
<h1 class="background-highlight"><span>The skippers escape</span></h1>
It is fault of pseudo element that is forced to break between two lines.
The cause is the way the effect is carried out, pseudo element ::before creates a single rectangle that has no way of splitting up to follow words flow. Posible solutions:
Make sure links never occupy more than 1 line. You can use
white-space: nowrap;
Redesign the effect applying box border to main element. For example:
.background-highlight {
width: max-content;
border-bottom:5px solid rgb(217, 255, 0);
}
<div class="background-highlight">THE SKIPPERĀ“S ESCAPE</div>
Pseudo-element solution
Use the bottom-positioning value on the pseudo-element instead of top. This forces the pseudo-element to be positioned at the bottom, instead of 50%from the top. I used bottom: -10px as that is the height of the pseudo-element, so it aligns perfectly.
Read more on position values: https://developer.mozilla.org/en-US/docs/Web/CSS/position
HTML-element solution
Instead of creating a pseudo-element, you could opt to make an HTML element instead.
Make a parent container, apply flex to it so the text and the line will align.
Make the .line-element a block element, so it will break into a new line.
You can still apply position: absolute and position: relative on the .line and the h2 if you want to position it in another way. Or you could simply use e.g. transform: translateY(5px) to move the line up a bit.
.background-highlight {
position: relative;
display: inline-block;
color: black;
text-align: right;
}
.background-highlight:after {
content: '';
position: absolute;
width: 100%;
height: 10px;
left: 0;
bottom: -10px;
background-color: #cef230;
z-index: -1;
}
/* Without pseudo */
.nopseudo {
display: flex;
}
.nopseudo h2 {
text-align: right;
}
.nopseudo .line {
height: 10px;
width: 100%;
background-color: #cef230;
display: block;
}
<h2 class="background-highlight">The Skippers <br>Escape</h2>
<div class="nopseudo">
<h2>The Skippers <br>Escape<span class="line"></span></h2>
</div>
I don't know how is your structure but this might help.
We just need two div elements, one as a container to setup the width property and the text holder in this case I will use a h2 tag.
Just mkae the ::after pseudo element as display and the .background-highlight's width can be width: match-content or 100% in this case if you just want to cover the text use match-content if you want to cover the width of the .title element use 100%
.title {
width: 90vw;
text-align: end;
}
h2 {
text-transform: uppercase;
color: #374650;
}
.fullwidth {
width: 100%;
}
.match {
width: match-content;
}
.background-highlight {
position: relative;
display: inline-block;
}
.background-highlight:after {
content: '';
display: block;
width: 100%;
height: 10px;
background-color: #cef230;
z-index: -1;
}
<div class="title">
<h2 class="match background-highlight">
The Skipper's <br>Escape</h2>
</div>
<div class="title">
<h2 class="fullwidth background-highlight">
The Skipper's <br>Escape</h2>
</div>

Trouble with nowrap and max-width on an absolutely positioned element

I'm guessing these two attributes don't actually work together, but my situation:
I'm trying to create a tooltip component. My tooltip is positioned absolutely, and as I don't know what the length of the content would be, has no width. So with width-related css, text just forms a tall, skinny column. I tried max-width, but on it's own, that does nothing. So I decided to try white-space: nowrap, and while it nicely doesn't wrap text, it also doesn't seem to honor max-width in a useful way, with text instead going out of the boundaries of the element.
I can't think of how to solve my problem, if there is a clean solution. I'd like to have an absolutely positioned div that expands to fit it's content until a maximum, at which point it wraps. One suggestion I saw was making the element a flexbox, but from what I can tell, that's not great with IE, so I don't think is viable in my situation. Any advice?
.wrapper {
position: relative;
display: inline;
}
.info {
position: absolute;
bottom: 1.2em;
left: 0;
}
<div class="wrapper">
<span>[ ? ]</span>
<div class="info">Any long text can go in here to test what goes wrong with wrapping.</div>
</div>
Avoid using white-space:nowrap as that will constrain your text to one line. max-width should work with a block level element with display absolute but not inside an inline element. To resolve this, I place the tooltip outside of your wrapper block and use javascript to position it at the mouse location.
Here is a simple solution for your issue. Click on "open tooltip" to display the tooltip and move the slider to change the value of max-width.
showContext = function() {
var e = window.event;
var posX = e.clientX;
var posY = e.clientY;
var info = document.getElementById("info");
info.style.top = posY + "px";
info.style.left = posX + "px";
info.style.display = "block";
}
changeWidth = function(value) {
var info = document.getElementById("info");
info.style.maxWidth = value + "px";
}
.wrapper {
position: relative;
}
.info {
position: absolute;
max-width:300px;
display:none;
border:1px solid black;
background-color:white;
}
.range {
margin:10px 0px 10px 0px;
display:block;
}
<div class="wrapper">
max-width slider
<input id="range" class="range" type="range" min="100" max="600" oninput="changeWidth(this.value)"/>
<input type="button" value="open tooltip" onclick="javascript:showContext();" />
</div>
<div id="info" class="info">Any long text can go in here to test what goes wrong with wrapping.</div>
I'm not exactly sure what your goal is as there are a lot of contradictory things going on. But I'll try and hopefully you can guide me towards your desired solution:
https://jsfiddle.net/q7dyf6xh/
.wrapper {
position: relative;
display: run-in;
}
.info {
position: absolute;
max-width: 200px;
white-space: pre-line;
}
Have a look at this fiddle, as you can see the tooltip now has a max-width. Have a look at what I'm using:
display: run-in;: Displays an element as either block or inline, depending on context
white-space: pre-line;: Sequences of whitespace will collapse into a single whitespace. Text will wrap when necessary, and on line breaks
For a better understanding of how things work look here:
white-space: If you use nowrap text will never wrap to the next line. The text continues on the same line until a tag is encountered!
This said your max-width is still working but with nowrap you overflow your element now. Try and give your element a background-color and you'll see that it actually is only as wide as your max-width defines.
See here how it overflows the element: https://jsfiddle.net/fcnh1qeo/
And now width overflow: hidden only the text inside your box will be displayed. Everything else is cut off! See here: https://jsfiddle.net/0qn4wxkg/
What I used now is display: run-in; and white-space: pre-line; as well as max-width: 200px which will give you hopefully your desired solution. Not knowing the context and code you using it is more of a guess than it is a answer. But maybe I can guide you towards a solution which fits your needs
Cheers!
Add a min-width:100% and a white-space: nowrap;
.wrapper {
position: relative;
display: inline;
}
.info {
position: absolute;
min-width: 100%;
white-space: nowrap;
}
<div class="wrapper">
<span>[ ? ]</span>
<div class="info">Any long text can go in here to test what goes wrong with wrapping.</div>
</div>
display="runin"The element generates a run-in box. Run-in elements act like inlines or blocks, depending on the surrounding elements. That is:
If the run-in box contains a block box, same as block.
If a block box follows the run-in box, the run-in box becomes the first inline box of the block box.
If an inline box follows, the run-in box becomes a block box.
pre-line Sequences of whitespace are collapsed. Lines are broken at newline characters, at <br>, and as necessary to fill line boxes.
The following table summarizes the behavior of the various white-space values:
The max-width CSS property sets the maximum width of an element. It prevents the used value of the width property from becoming larger than the value specified by max-width.
.wrapper {
position: relative;
display: run-in;
top: 100px;
}
.info {
position: absolute;
bottom: 1.2em;
left: 0;
max-width: 200px;
white-space: pre-line;
background-color: #ddd;
}
Not that ling ago i had a very similar problem myself. I fixed it using flexbox what is already suggested in the comments here.
My code looks like this:
.has-tooltip {
display: inline-flex; align-items: flex-start
}
.has-tooltip > .tooltip {
padding: 1em;
max-width: 300px;
background: #bdc3c7;
word-wrap: break-word;
transform: translate(-50%,-110%)
}
I also copied this into this fiddle just in case you want to have a look at it. (:
You are correct that this does not work.
Here's a solution that works if you are allowed to use BR tags. I have worked on tooltips many times and this is the best solution that I have.
Codepen:
https://codepen.io/btn-ninja/pen/JNJrgp
It works by using white-space nowrap with a css translate:
<button type="button" class="btn btn-block hasTooltip">
Tooltip on top
<i class="tip">Most tooltips are short<br>but you can add line breaks.</i>
</button>
<button type="button" class="btn btn-block hasTooltip right">
Tooltip on the right.
<i class="tip">Tooltip on right<br>vertically centered.</i>
</button>
.hasTooltip .tip {
position: absolute;
bottom: 100%; left: 50%;
transform: translateX(-50%); }
.hasTooltip.right .tip {
bottom: auto; left: 100%; top:50%;
transform: translateY(-50%); }
The translate allows the absolutely-positioned tooltip to horizontally or vertically center itself vs the content. White space with a BR achieves wrapping for long content while allowing shorter tooltips to match width of the tooltip text.
Here's the full css:
.hasTooltip {
position:relative; }
.hasTooltip .tip {
display:block;
background: #333; color: #fff;
box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.5);
font-size:inherit;
font-style:normal;
line-height: 1rem;
text-align:center;
padding: 8px 16px;
border-radius:4px;
margin-bottom:5px;
pointer-events: none;
position: absolute;
bottom: 100%; left: 50%; transform: translateX(-50%);
opacity: 0;
transition: opacity .34s ease-in-out;
white-space:nowrap;
z-index:99; }
.hasTooltip .tip:before {
content: "";
display:block; position:absolute; left:0; bottom:-5px;
width:100%; height:5px; }
.hasTooltip .tip:after {
border-left: solid transparent 6px;
border-right: solid transparent 6px;
border-top: solid #333 6px;
bottom: -4px;
content: "";
height: 0;
left: 50%;
margin-left: -6px;
position: absolute;
width: 0; }
.hasTooltip:focus .tip,
.hasTooltip:hover .tip {
opacity: 1;
pointer-events: auto; }
.hasTooltip.right .tip {
bottom: auto; left: 100%; top:50%; transform: translateY(-50%);
margin-bottom:0;
margin-left:5px; }
.hasTooltip.right .tip:before {
left:-5px; bottom:auto; }
.hasTooltip.right .tip:after {
border-left: 0;
border-top: solid transparent 6px;
border-bottom: solid transparent 6px;
border-right: solid #333 6px;
bottom:auto;
left: -4px;
top:50%;
margin-left: 0;
margin-top: -6px; }

Set space/margin all around an absolute <div> which is inside a scrollable <div>

I'd like to set a margin all around a <div> with a position:absolute inside a scrollable <div> to let some free space between the inside div and the scrollable area boundaries (right and bottom).
I tried something like this but with no luck:
<div style="overflow:scroll">
<div style="position:absolute; margin-right:100px; margin-bottom:100px">DRAG ME</div>
</div>
Demo here: https://jsfiddle.net/ayft01x0/
Only the margin-bottom works, and only in Chrome.
You can also imagine that there are other elements inside the scollable div and that they should stay clickable even if they are masked by the margin of the "drag me" element (which should be the case when using CSS margins).
I'm looking preferably for a CSS-only solution that works in Webkit browsers.
Any ideas?
Absolute positioning changes the way margins work, but you can get the effect you're after with borders:
We add a border to the left and the right. This interferes with the border you already had on the draggable element, so we add a pseudoelement to take care of the design. The pseudoelement covers up the "drag me" text, so we add a wrapper around that content and fix the z indices
Here's an update to your fiddle, and here's a snippet of the essential css
#container {
position: relative;
width: 200px;
height: 200px;
border: solid 1px black;
background-color: white;
}
#box {
position: absolute;
border-right: 100px solid transparent; /* changed this */
border-bottom: 100px solid transparent; /* changed this */
outline: 1px solid red; /* just for demo purposes */
width: 80px;
height: 80px;
left: 50px;
top: 50px;
/* dropped the border and background styles */
}
#box span { /* added this element */
position: relative;
z-index: 1;
}
#box:before { /* added this element */
content: '';
position: absolute;
z-index: 0;
width: 80px;
height: 80px;
/* placement adjusted to take the border into account */
left: -2px;
top: -2px;
/* border and background styles moved from #box to here */
border: solid 2px #666;
border-radius: 10px;
background: #ccc; /* shaved off a couple bytes by dropping the -color */
}
<div id="container" style="overflow:scroll">
<div id="box">
<span>DRAG ME</span><!-- added this wrapping element so that it can get a z-index -->
</div>
</div>
Note that I've kept your initial positions for the draggable box, but I would probably actually do it like this. The negative margins are just half the element's dimensions. This way if you tweak the size of #container you don't have to recalculate #box's starting position
#box {
...
width: 80px;
height: 80px;
left: 50%;
top: 50%;
margin-left: -40px;
margin-top: -40px;
}
There is a workaround by using an encapsulating div with inner padding and make it transparent to the mouse interactions using the pointer-events property.
<div style="overflow:scroll">
<div style="position:absolute; padding-right:100px; padding-bottom:100px; pointer-events:none">
<div style="pointer-events:all">DRAG ME</div>
</div>
</div>
Demo here: https://jsfiddle.net/1axtonez/
The easiest way to achieve this is to create an invisible CSS ::before pseudo-element that covers the box plus a padding, and to make it transparent to the mouse interactions using the pointer-events property:
div.box::before{
content: '';
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
padding-right: 100px;
padding-bottom: 100px;
pointer-events: none;
/* background-color: rgba(255,0,0,0.2); // to understand what is going on */
}
Demo here: https://jsfiddle.net/rmxwwyno/
Be warned that it's not working when the box has an overflow property that is not set to visible.

Why doesn't inset box-shadow work over images?

I have a container that uses inset box shadow. The container contains images and text. The inset shadow apparently does not work on images:
The white section here is the container. It contains a white image, and there is inset box shadow applied to it.
body {
background-color: #000000;
}
main {
position: absolute;
bottom: 0;
right: 0;
width: 90%;
height: 90%;
background-color: #FFFFFF;
box-shadow: inset 3px 3px 10px 0 #000000;
}
<main>
<img src="https://upload.wikimedia.org/wikipedia/commons/d/d2/Solid_white.png">
</main>
Is there a way to make the inset box shadow overlap images?
Just to chime in on this, because I was just creating something similar...
I hate polluting my markup with extra elements for the sake of styling, so the CSS solution is to use the :after pseudo element:
main::after {
box-shadow: inset 3px 3px 10px 0 #000000;
content: '';
display: block;
height: 100%;
position: absolute;
top: 0;
width: 100%;
}
<main>
<img src="https://upload.wikimedia.org/wikipedia/commons/d/d2/Solid_white.png">
</main>
It's probably too late for what you were trying to do, but is the better solution in my estimation.
Because the shadow is part of the parent container it renders below the image. One alternative is to have a div which places a shadow overtop the image like so:
body {
background-color: #BBB;
}
main {
position: absolute;
bottom: 0;
right: 0;
width: 90%;
height: 90%;
background-color: #FFFFFF;
border-radius: 20px;
}
main img {
border-radius: 20px;
}
.shadow {
position: absolute;
width: 100%;
height: 100%;
box-shadow: inset 3px 3px 10px 0 #000000;
border-radius: 20px;
top: 0;
left: 0;
}
<main>
<img src="https://upload.wikimedia.org/wikipedia/commons/d/d2/Solid_white.png" />
<div class="shadow"></div>
</main>
Edit: I've updated the fiddle to include border radius on the shadow and on the img which solves the issue identified in the comments.
The reason it's not overlapping is because the image is inside the div, so the image is on top of it. The image is higher (closer to the user) than the div.
You can change the image to use position: relative; z-index: -1, and have the containing div use a border instead of setting background color on the body. You'll need to use box-sizing: border-box to include the border in the width of the div.
DEMO
body {
background-color: #FFF;
}
main {
position: absolute;
bottom: 0;
right: 0;
width: 100%;
height: 100%;
border: 60px solid black;
box-shadow: inset 3px 3px 10px 0 #000000;
box-sizing: border-box;
}
img {
z-index:-1;
position: relative;
}
For those, who're using absolute-positioned, full-size :before/:after pseudo elements, consider using pointer-events: none on the pseudo-element so the original elements remain clickable.
The best way to achieve this in 2020 would be to use mix blend mode on the image. use the box-shadow on the parent element of the img and use mix-blend-mode: multiply.
You could set the image as the div's background instead:
background-image:url(http://www.placehold.it/500x500)
jsFiddle example
https://stackoverflow.com/a/21415060/6235358
that's a great way to do it but we can do it in a better way using the ::after pseudo-class so you'll not have to add an empty <div> to your HTML
As Rilus mentioned we could use a pseudo class. Unfortunately this does not seem to work on an img tag for some reason however we can use a combination of inner and outer containers to achieve the affect we need.
.outer:hover .inner:after {
position: absolute;
content: '';
color: white;
display:block;
bottom: -0px;
right: -0px;
width: 100%;
height: 100%;
z-index: 11;
border: solid 10px red;
}
http://jsbin.com/kabiwidego/1/
not sure about ie 10 though as it seems to handle pseudo classes that are absolutely positioned slightly differently to most browsers.
One simple fix if you are clever with your decimals is to store your content in a separate div which you then select and implement a certain number of pixels from the top.
For example, let's say your header has a height of 50px. You could begin your #content div id 53.45px from the top (or whatever height your drop shadow is) and then your shadow would appear above the images.
One issue with this is that if you are using a rather transparent shadow, the more transarent it is the more tacky it may look by implementing this css.
In practice the code would be as follows:
HTML:
<header>
Whatever's in your header
</header>
<div id="content>
Page content
</div>
CSS:
header {
height: 50px;
box-shadow: 0 5px 5px rgba(0,0,0,1);
}
#content {
top: 55px;
}
Even if i'm late for the party, I had the same issue these days and worked on a solution. For me, the best solution (mobile friendly) is this one:
JSFiddle:
.image-inset-container {
margin-bottom: 30px;
}
.image-inset-shadow {
position: relative;
}
.image-inset-shadow img {
border-radius: 20px;
}
.image-shadow {
position: absolute;
width: 100%;
height: 100%;
box-shadow: inset 3px 3px 10px 0 #000;
border-radius: 20px;
top: 0;
left: 0;
}
<body>
<h4>Reimagined Web Design</h4>
<p>With your input and business goals in mind, we bring your brand to life through custom human-facing graphics and
visual elements targeted toward your audience for good user experience and created in future-forward technology,
guaranteeing a successful new web design.</p>
<div class="image-inset-container">
<div class="image-inset-shadow"><img src="https://upload.wikimedia.org/wikipedia/commons/d/d2/Solid_white.png" alt="img1" />
<div class="image-shadow"></div>
</div>
</div>
<p>We initiate a collaborative process where your team is involved in every step to create a frictionless and
delightful
experience for your customers. Our designers immerse themselves in your industry and your brand aesthetic to
deliver
a website that represents your business while achieving your goals for a connected future.</p>
</body>

PNG shadow with fluid height

Due to browser performance implications I can't use box-shadow CSS property because I have many similarly looking elements on my page that should have same looking style including shadow. That's the reason I would like to implement shadows using traditional PNG imagery.
Facts
My elements have predefined and more importantly fixed pixel width
They have fluid height (auto) depending on their content
They have content directly in the element and some child elements will be positioned outside their border
CSS3 can be used but performance-critical parts (gradients, shadows...) should be avoided
CSS pseudo elements can be used without limitation
Requirements
There should be no additional wrapper element added in order to have fluid shadow
Application should run smoothly on mobile browsers - shadows seem to slow down performance significantly on mobile devices since their processing power is much lower than desktop computers.
Possible direction
I thought of using :before and :after pseudos to display top-to-bottom and bottom shadows on the containing element, but these pseudos display within their parent element and positioning parent z-index higher than these children has no effect.
Visual demo of end result
This JSFiddle Demo in pure CSS3 that I would like to achieve but using PNG shadows. In reality there are numerous of these boxes so you can imagine mobile browsers are struggling with all these shadows.
Item is one such box (see blow) that needs PNG shadow. Left menu is child element positioned outside of the box.
Display in Chrome
HTML
<div class="item">
<menu>
<li>Yes</li>
<li>No</li>
<li>Maybe</li>
</menu>
<div class="content">
Some content
</div>
</div>
CSS3 LESS
.item {
position: relative;
width: 300px;
background-color: #fff;
box-shadow: 0 0 10px #ccc;
margin: 20px 20px 20px calc(20px + 3.5em);
min-height: 5em;
&:first-child {
margin-top: 0;
}
&:after {
content: "";
position: absolute;
top: 0;
left: 0;
width: 10px;
height: 5em;
background-color: #fff;
}
menu {
position: absolute;
top: 0;
left: -3.5em;
width: 3.5em;
margin: 0;
border: 0;
padding: 0;
list-style: none;
background-color: #fff;
box-shadow: 0 0 10px #ccc;
li a {
display: block;
text-align: center;
padding: 2px 0;
}
}
.content {
padding: .75em 1em;
}
}
Probably I am missing something, but looks like you want something in this way:
demo
The CSS is
.base {
width: 300px;
height: 150px;
font-size: 100px;
font-weight: bolder;
background-color: lightgreen;
position: relative;
z-index: auto;
}
.base:after {
content: '';
position: absolute;
top: 30px;
left: 30px;
background-color: green;
z-index: -1;
width: 100%;
height: 100%;
}
.child {
position: absolute;
left: 150px;
top: 50px;
border: solid 1px black;
color: red;
}
And just change the background of the :after to your image.
I have applied this solution to your fiddle.
The relevant CSS is for the before pseudo element:
.item:before {
content: "";
position: absolute;
top: -10px;
left: -10px;
right: -10px;
bottom: -10px;
z-index: -1;
background-image: url(http://placekitten.com/100/100);
background-repeat: no-repeat;
background-size: 100% 100%;
}
I have used a kitten picture, that is being scaled to cover all the needed size. Just change that to whatever you want.
I needed to do it that way because I had onky a pseudo element available.
The key for that to work (and where you probably had the difficulty) is to add z-index: auto to .item
Updated demo
Well, I had said that it wasn't posible, but I have find a way.
The standard technique would be to use 2 elements, just to avoid stretching the image (as you said). The problem is that we only have 1 pseudo element available.
The solution then would be to use 1 pseudo element, but with 2 backgrounds, to solve the issue.
CSS (only relevant part)
.item:before {
background-image: url(http://placekitten.com/320/10), url(http://placekitten.com/320/500);
background-repeat: no-repeat;
background-size: 100% 9px, 100% calc(100% - 9px);
background-position: left bottom, left top;
}
We will need an image (the first one) only 10 px in height, to cover the bottom shadow. And another one, with enough height to cover the maximumitem posible, and that will be used for the remaining part of the shadow. The dark part is that we need now a calc() height, with limited support. (anyway, better than border image)
demo 3

Resources