Bootstrap 3: Stacking Order in Navbar with Custom Image Styling - html

I have been trying to port the functionality of a simple rounded image class to work with Bootstrap v3.3.7. Essentially, I nest an img inside of a div, and apply an inset border with alpha-transparency. It works great, as seen in this simple jsFiddle:
Rounded Avatar jsFiddle
CSS:
.inset {
width: 48px;
height: 48px;
border-radius: 50%;
box-shadow:
inset 0 0 0 2px rgba(255,255,255,0.6),
0 1px 1px rgba(0,0,0,0.1);
}
.inset img {
border-radius: inherit;
width: inherit;
height: inherit;
display: block;
position: relative;
z-index: -1;
}
And the markup would look like:
<div class="inset">
<img src="http://rs775.pbsrc.com/albums/yy35/PhoenyxStar/link-1.jpg~c200">
</div>
However, when I attempt to use this inside of a navbar in Bootstrap v3.3.7, I am encountering what I presume to be a stacking issue that I just cannot resolve. As in the sample above, I had started out with the img having a z-index of -1, so that it would sit below the div. This puts it underneath the navbar. So, I had assumed that I could simply push up the z-index of the div and the img to a physical value, trying 998 for the img and 999 for the div.
When I do that, however, the div does not show. If I am to push the img below the div, however, I see the div and the border being correct - I just can't get it to display above the image. I've create a minimal example of this behavior as a Bootply.
Bootply with Avatar Rounding and Missing Inset Border
I am at a loss to explain this, (and my front-end skills leave a bit to be desired). Can only assume that there is something simple that I have to be missing. Any help would be greatly appreciated.
Thank you, in advance.

By giving it a z-index:-1, you're sending your image below the current stacking context. Because it doesn't have one, and because it doesn't have any parent with a background, it renders as you expect it to, but you shouldn't expect it to. And without giving it a z-index:-1, you can't make it render below its parent. But, again, it's not just below the parent, it's below the stacking context.
Here's what happens when I simply put your example inside: a div with background.
The problem is you want an effect applied to the parent to render above the child.
You could (and should) use either a sibling/child of the child, which could be either an unused pseudo-element of the parent or a pseudo-element of the child. But, since the child is an <img /> tag, it cannot have pseudo-elements, so we'll stick to the parent:
.inset {
width: 100px;
height: 100px;
position: relative;
border-radius: 50%;
}
.inset::after {
width: inherit;
height: inherit;
border-radius: inherit;
box-shadow:
inset 0 0 0 2px rgba(255,255,255,0.6),
0 1px 2px rgba(0,0,0,0.1);
position: absolute;
top: 0;
left: 0;
content: '';
}
.inset img {
border-radius: inherit;
width: inherit;
height: inherit;
display: block;
}
<div style="background-color: red;">
<div class="inset">
<img src="http://rs775.pbsrc.com/albums/yy35/PhoenyxStar/link-1.jpg~c200">
</div>
</div>
This will work anywhere you place it, regardless of current z-index or stacking context.
The other option, if you insist on Doing-it-wrong™ would be to wrap the current parent inside an element that would create a new stacking context
position:relative;
z-index: 0;
... but I find it harder to maintain, bloated and probably confusing for anyone not familiar with how stacking contexts work. This technique comes in handy when adding color overlays to images (instead of using an extra element, you just use the wrapper background). But, again, it confuses people so it shouldn't be used.

Related

Z-index "stacking" in creating a shadow

I have the following HTML structure that I'd like to keep nested:
<div class="parent">
<div class="shadow">Shadow here!</div>
</div>
CSS:
.parent {
background: blue;
z-index: 2;
height: 200px;
}
.shadow {
background: lightgrey;
z-index: 0;
opacity: 0.4;
position: relative;
top: 194px;
}
Essentially, I want the div .shadow to be underneath the div .parent. If you look at the rendering at the below link, you can see that part of the parent's blue background goes through the shadow; instead, I'd like the parent element to cover that overlapping part (stacked on top of, I guess you can say):
https://jsfiddle.net/9ya7kb67/
How could I do this? I'm fiddling around with z-index, but that isn't helping.
This is simple... give your shadow z-index property negative value like this. You can also manage z-index by giving higher value. Or you can use box-shadow property to make shadow.
.parent {
background: blue;
z-index: 2;
height: 200px;
}
.shadow {
background: lightgrey;
z-index: -1;
opacity: 0.4;
position: relative;
top: 194px;
}
You can use box shadow with CSS3 https://css-tricks.com/snippets/css/css-box-shadow/
CSS box-shadow works by creating a shadow behind an element. Thus, the element is already on top of the shadow. Here, z-index is not required.
the code:
.parent {
background: blue;
height: 200px;
box-shadow: 0 8px 0 4px light grey;
}
is doing the same thing regardless if you include z-index or not.
I'm not sure if it is the answer you are looking for, but you can always use the CSS property box-shadow on your parent to get a 'shadowy' effect.
See this fiddle here
You can find box shadow generators online to make your life easier, such as this one
.shadow requires a negative z-index value as z-index is inherited from it's parent and is comparatively displayed. z-index:0; gives it the same overall z-index the parent has, and as the child was declared after the parent, it is therefore on top. This means that by setting it to z-index:-1 you are placing the shadow behind the parent.
However, if you simply want a box-shadow I would recommend actually using CSS3 Box Shadows instead of creating additional elements.
Because the shadow is INSIDE of the parent, there is no way to make the parent appear on top of whatever is inside. This is because in CSS a child element inherits the z-index of its parent as a BASE z-index. It can have its own z-index but it can never be less than its parent.
EDIT: Box shadow solution -
https://jsfiddle.net/9ya7kb67/3/
.parent {
background: blue;
z-index: 2;
height: 200px;
box-shadow: 0 8px 0px 4px lightgrey;
}
EDIT2: I stand corrected about it being impossible to put a child below a parent. You CAN actually do this, but that is assuming that the parent does not already have a z-index set. If the parent has a z-index, THEN it is impossible to place it on top of a child.

How do I position an image to the top left corner of a div, and keep it there if the div moves?

I apologize if this has been answered time and time again. I remember searching thoroughly for an answer a couple years ago when I first wrote up my website script, but I couldn't ever find one. The same for now.
Recently I reworked my website's script so I can host it onto Weebly. Here is one of the four pages of my site that I need help with. As you can see, the images that pop up when the thumbnail is hovered over are absolutely positioned. For most computer resolutions and/or browsers, this will have the image appear out of the designated box.
How could I position them to the inner top left corner of the div? Or better yet, horizontally and vertically centered within it?
<section id="Sizes" style="float: left">
<a href="#Space">
<img class="Small" src="/files/theme/SampleD_Fun_Icon.png" width="150" height="150" alt="Sample 1: Day of Fun" />
<img class="Large" src="/files/theme/SampleD_Fun.png" width="150" height="150" alt="Sample 1: Day of Fun" />
</a>
...
</section>
<a id="Space"></a>
<span class="Popup">Hover over thumbnail to display sample artwork.</span>
<br style="clear: left" />
a:hover img.Small
{
border: 5px solid #21568b;
margin: 10px;
text-decoration: none;
}
section#Sizes a img.Large
{
border-width: 0;
height: 0;
left: 438px;
position: absolute;
top: 326px;
width: 0;
}
section#Sizes a:hover img.Large
{
height: 526px;
left: 438px;
position: absolute;
top: 326px;
width: 520px;
}
.Popup
{
border: 3px solid;
float: left;
height: 272px;
margin: 8px 20px 0px 0px;
padding-top: 254px;
text-align: center;
width: 520px;
}
Thank you for your time. :)
Your whole design is a bit fragile, and I wouldn't recommend building this this way in the first place, but you're looking for practical answers, so here's the smallest change I can think of that fixes your problem:
1) Add this to your style sheet:
body { position: relative; }
2) On line 40 from your main_style.css, change top: 326px to top: 316px and left: 438px to left: 428px, so that it becomes like this:
section#Sizes a:hover img.Large {position: absolute; top: 316px; left: 428px; width: 520px; height: 526px;}
How does that work?
Your images are place using absolute positioning. By default, that works relative to the viewport (the window). But by turning the body into position relative, it becomes a containing block, and position absolute is relative to the nearest containing block ancestor.
So now, your images are fixed within the body element, instead of being fixed relative to the window. Since the margins of the body element is what's changing size when you resize the window, that makes the various pieces of your content fixed relative to each other. You then just need to remove 10px from the top and left side, since that's the size of the border of your body element, and we're now measuring from inside the border.
TLDR: You can't do this in pure CSS.
You can easily position the image inside the container div if you place the image element inside the div element, and then use absolute positioning like top: 0; left: 0; (or with a number of other methods). But then you'd need JavaScript to correlate the hovered thumbnail with the popup full-size image.
Alternatively, you can have the full-size image be nested in the thumbnail element (like you currently have), but then you'd need JavaScript to position the full-size popup image inside the container div.
Of the two alternatives, I recommend the first: put all the popup images inside the target container, and use JavaScript to show or hide them when a thumbnail is hovered. Correlating the thumbnail and the full size image via JavaScript is going to be easier then writing positioning code.
I see you're using jQuery already so why not do something like this?
$('.Small').on('mouseover', function(){
$('.Popup').empty().html($(yourtarget).attr('img' , 'src'));
});
$('.Small').on('mouseout', function(){
$('.Popup').empty().html('Hover over thumbnail to display sample artwork.');
});
Just because everyone was saying it can't be done with pure css, I wanted to demonstrate that it can, and it is even quite easy. Have a look at the folowing example:
http://jsfiddle.net/aafa2zp5/
<div id='images-wrapper'>
<ul>
<li>
<img class='small' src='http://placehold.it/50/ff0000'/>
<img class='big' src='http://placehold.it/300/ff0000'/>
</li>
<!-- and some more similar thumb / image groups -->
</ul>
<div class='preview-area'></div>
</div>
CSS (or the relevant part at least)
#images-wrapper {
position: relative;
}
.big {
display: block;
position: absolute;
top: 54px;
right: 54px;
opacity: 0;
transition: opacity .5s;
}
.preview-area {
width: 350px;
height: 350px;
border: 4px solid blue;
position: absolute;
top: 21px;
right: 21px;
}
li:hover .big {
opacity: 1;
}
The key is to set a position relative to the wrapper (and keep all of the descendants as their default static). Then you can use this to position the preview area and the big images against by setting them to postion absolute and carefully calculating the correct postion. I even added a cross fade, just because it is so easy, but you could just as well work with display block / none if you prefer.
For smaller screens you may want to alter the dimensions and positioning inside a media query, but it still should be doable (though depending on the hover state is perhaps not the best idea on a touch device)
I hope you get the idea and you can figure out how to apply this technique to your own site. Feel free to ask if you want me to explain further or when you get stuck.

How a big CSS border flows out of the parent element

[ Screenshot ]
I have two HTML elements, one of them (the black one) is the parent of the other (the one marked with red line). The size of the child is clearly not bigger than its parent. However, its very big border is making it overflow out of its parent element, the overflow direction is to the right and bottom of the parent. Can I make it overflow to the left and top too? That'll make it appear nicer than it's currently. I've read every single CSS property and didn't find anything to control that behavior.
<div style="width: 426px; height: 611px; position: relative; background-color: black;">
<div style="position: absolute; width: 400px; height: 317px; top: 85px; left: 0px; display: block; border: 60px solid red;"></div>
</div>
I don't want to make it in the center, because it has a custom position.
JS Fiddle: http://jsfiddle.net/Ng3Pu/
you need to use CSS3
Box-sizing: Border-box;
but check the compatibility support

extending background horizontally outside div

I have some css:
.note {
background: red;
}
.note > div {
max-width: 780px;
margin: 0px auto;
position: relative;
padding-left: 20px;
border: 1px solid black;
}
.note > div:before {
content: '⚠';
position: absolute;
left: 0px;
}
And a corresponding html like:
<div class='note'><div>Foobar</div></div>
This creates a red line across the screen, but the content will be only in the center area. It works well so far. But I want the whole content to be in a 800px width area, so I add a container:
#container {
max-width: 790px;
margin: 0 auto;
background: green;
border-radius: 10px;
padding: 5px;
}
And some html:
<div id='container'>
<p>Lorem ipsum</p>
<div class="note"><div>foo</div></div>
<p>Foobar</p>
</div>
Of course, note won't work here (the red line doesn't extend beyond the green container). I've been trying to come up with something, but I couldn't. I can't just close the container, place my note, and open another because border-radius and (and also box shadow, but I left it out from the example) would break then. Using a negative margin on .note also doesn't work, because it adds horizontal scrollbars. I could make .note position: absolute;, but then my note would overlap whatever comes after it.
Any ideas how could I solve it?
Update: Here's a JSFiddle. The second version is what I actually want, except that it creates a vertical scrollbar. The third is like Robert's solution, and the only problem is that it takes the div out of flow, and I'd like to avoid hacks like adding a margin-top to the following element because I don't know the length of the note in advance.
.note {
background: red;
position: absolute;
left:0;
right:0;
}
Here's a jsfiddle:http://jsfiddle.net/ySVZb/
Note that I changed some widths so it's easier to see in the jsfiddle screen, but the size is irrelevant. Also note that because I've taken the note div outside the normal flow, you will need to add an appropriate margin to anything that follows or it will fall behind the note div. Some generic like .note + * {margin-top: 2em} will work in some cases, but it will override any margin top already on that element, in those cases you'll need a more specific fix like .note + p {margin-top: 3em;} jsfiddle showing that here: http://jsfiddle.net/ySVZb/1/

How to make an element with variable width always stick out a specific width?

I have a div that has a variable width, depending on its content. I want to use it for a menu bar that slides in from the side of the page when the user clicks it, so it has to stick out. I want it to stick out exactly 16px (because the arrow image has that size), no matter how wide it actually is.
How can I realize that without using JavaScript?
EDIT:
Thanks for your answers! But it came to my mind that I could do it just like I did with the navbar on that site – modify the width instead of sliding it in.
See here: http://dev.mezgrman.de/tagwall/
The easiest way to do that is to add another class to your menu item when it is collapsed and set another width there and a text indent like so (instead of write again all your css in a new class)
.collapsed {
width: 16px;
text-indent: -9999px;
background: url("/images/arrow_left.png") no-repeat scroll right center rgba(0, 0, 0, 0.85);
}
Now the only thing you have to do in javascript is to add and remove that class depending on the user's click. (You won't get rid of javascript. because css doesn't know when you click an element)
http://jsfiddle.net/LruWn/
No matter how long the .box is, it will always overlap the .container only by exactly 16px:
html:
<div class="container"><div class="box">text</div></div>​
css:
.container {
position: relative;
outline: 1px solid red;
width: 100px;
height: 100px;
}
.box {
width: 70px;
position: absolute;
left: 100%;
margin-left: -16px;
outline: 1px solid black;
}​
Add overflow: hidden; to .container to see how it might look like in action.
I solved my problem by modifying the width of my element now. Silly me.