Text still visible from lower parent element - html

I have two elements, an anchor and its pseudo-element. In the code snippet below, the pseudo-element is positioned behind its parent element. When it is hovered, the pseudo-element scales.
.btn:link,
.btn:visited {
text-transform: uppercase;
text-decoration: none;
padding: 15px 40px;
display: inline-block;
border-radius: 100px;
transition: all 0.2s;
box-shadow: 0 3px 5px rgba(0, 0, 0, 0.4);
position: relative;
margin: 40px;
}
.btn:hover {
transform: translateY(-10px);
box-shadow: 0 20px 20px rgba(0, 0, 0, 0.2);
}
.btn-white {
background-color: #fff;
color: #777;
}
.btn::after {
content: "";
display: inline-block;
height: 100%;
width: 100%;
border-radius: 100px;
position: absolute;
top: 0;
left: 0;
z-index: -1;
transition: all 0.2s;
}
.btn-white::after {
background-color: red;
}
.btn:hover::after {
transform: scale(1.5);
}
Example
I know that when the button is not hovered, the pseudo-element is below the parent because they are in the same stacking context, and the pseudo-element has a z-index of -1. However, when the button is hovered, they are in different stacking contexts due to the parent using the transform property. Therefore, the pseudo-element covers the parent. However, the "Example" text from the parent element is still visible. Why is that?

There are three elements for the html. The <a> itself, the ::after and the text node "Example". ::after is a child to the <a>
In normal state, <a> is a positioned element but since z-index is not set, a new stacking context will not formed. ::after is also an positioned element with z-index -1, it has a stacking context and stay under <a>. In this state, both <a> and ::after under root stacking context.
When hover, transform is applied to <a>, a stacking context is formed. ::after and "Example" text node will be confined under this stacking context. Text node has auto z-index, which is greater then ::after's -1. Text node will be render above ::after.

.btn:hover::after {
transform: scale(1.5);
z-index: 1;
}
I think this overrides the stacking order of the text

Related

How to override inline CSS background-color opacity, but not the color?

The web page has a list of blocks like below. The background color of each block is done inline with 0.5 opacity. The 0.5 opacity is the problem. I need it to be completely opaque. I'm using the Stylish Chrome extension, and I need to do it with external CSS.
<a class="pizza" style="background-color:rgba(255, 255, 0,0.5);>this is yellow</a>
<a class="pizza" style="background-color:rgba(255, 0, 0,0.5);>this is red</a>
The only way I know how to change the opacity also involves changing the color for every block to the same. But each block in the list has it's own color, and needs to keep it's own color. How can I change the opacity of all blocks without also changing the color?
I would want something like this:
a.pizza {
background-color: rgba(, , , 1);
}
Or like this:
a.pizza {
background-color-opacity: completely opaque !important;
}
I've come up with a bit of a hack. It doesn't get you back to 100% opacity but pretty close.
The trouble is, without JavaScript, there's no way to find out what the colour is and take action based on that. So what you can do instead, is use CSS's inherit for the background color of child elements and layer them up to increase the overall perceived opacity of the main element.
So by adding two pseudo elements that inherit the background color and positioning them behind the main element you get very close to 100% opacity:
/* For the demo */
.pizza {
display: inline-block;
vertical-align: top;
width: 120px;
height: 120px;
}
/* Add relative positioning so we can position the absolute children correctly */
.pizza.new {
position: relative;
}
/* Add two pseudo elements behind that inherit the background color */
.pizza.new::before,
.pizza.new::after {
/* Sizing and positioning */
display: block;
position: absolute;
content: '';
top: 0;
right: 0;
bottom: 0;
left: 0;
/* Take the background color of the parent */
background: inherit;
/* Make sure they're not obscuring the content */
z-index: -1;
}
<a class="pizza" style="background-color: rgba(255, 255, 0, 0.5);">
This is yellow (before)
</a>
<a class="pizza" style="background-color: rgba(255, 0, 0, 0.5);">
This is red (before)
</a>
<a class="pizza new" style="background-color: rgba(255, 255, 0, 0.5);">
This is yellow (after)
</a>
<a class="pizza new" style="background-color: rgba(255, 0, 0, 0.5);">
This is red (after)
</a>
You can try to approximate it with mix-blend-mode and you will have an opaque color:
.pizza {
display: inline-block;
padding: 50px;
position: relative;
z-index: 0;
}
.pizza:before {
content: "";
position: absolute;
top: 0;
right: 0;
left: 0;
bottom: 0;
background: #fff;
z-index: -1;
mix-blend-mode: multiply;
}
body {
background: linear-gradient(to bottom, grey 50%,blue 0);
}
<a class="pizza" style="background-color:rgba(255, 255, 0,0.5);">this is yellow</a>
<a class="pizza" style="background-color:rgba(255, 0, 0,0.5);">this is red</a>
The easiest way I can think of, if you don't want to edit the colors themselves, would be to use a CSS pseudo-element to add an opaque white background (or whatever background color you want) behind every div with a colored background. You could use something like
div.pizza::after {
content: '';
position: absolute;
height: 100%;
width: 100%;
top:0; left: 0;
background: #FFF;
}
You may need to tweak the z-index depending on your particular CSS.

CSS transition, position keeps moving on hover

I have a simple css transition on the right property for a button which simply moves an arrow when you hover. The problem is that when you hover, it's not transitioning properly and if you refresh (or re-run) the JSFiddle, then you will notice that the arrow moves position after hovering.
It's like it moves back, then forwards then back again?
This appears to only happen in Firefox.
JSFiddle
Found the problem. Your span is inline, and giving it position: relative caused the issue.
Simply change to inline-block and you're good to go:
.genericBtn span {
display: inline-block;
position: relative;
}
How about using a more subtle approach by using CSS pseudo elements:
.genericBtn {
background: #ffffff;
color: #c40009;
border: 1px solid #c40009;
font-size: 20px;
margin: 10px 0 0;
padding: 20px 50px 20px 30px;
width: 300px;
position: relative;}
.genericBtn::after {
content: ">";
position: absolute;
right: 37%;
transition: all .3s ease-in;
}
.genericBtn:hover::after {
transform: translate(10px,0); }
Here is a Fiddle

How to create a border that does't add a margin?

I'm new to HTML/CSS, and I'm learning Bootstrap.
I'm coding a Bootstrap navbar and I have a small difficulty, here's a fiddle of the work I have done.
In the HTML code there is the normal markup that goes into building a TWBS navbar, and I have added code to change the color of the active tab:
.navbar-nav a.active {
-webkit-transition: .2s;
-o-transition: .2s;
transition: .2s;
border-top: 2px solid #212121;
}
Problem: The text wrapped within the<a> tag is now slightly pushed down and I am noticing that the border-top CSS property functions more like a margin-top property.
How do I avoid this and create a border that doesn't add the margin?
You can style :before pseudo element of the active a and position it relatively to the parent element:
.navbar-nav a.active:before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 2px;
}
Demo: http://jsfiddle.net/djuj5jte/5/
You could use an inset box shadow:
box-shadow: inset 0px 3px 0px 0px #212121;
This has the benefit of not changing the elements size OR requiring a pseudo element but sadly isn't supported in <=IE8 ;(
See: http://jsfiddle.net/djuj5jte/3/
You can add
html {
box-sizing: border-box;
}
*, *:before, *:after {
box-sizing: inherit;
}
so that the border will be part of the element width.
Useful link: https://css-tricks.com/box-sizing/

Make div with opacity:0 have no physical dimensions

I'm creating a function where you hover over a div, which will result in another div appearing; a simple, CSS-only pop-over.
However, whenever the pop-over-div has an opacity:0, it still has a physical height and width, rendering other divs under the pop-over unreachable.
I know I can work with display:none and display:block, but this will remove the possibility of adding a smooth "arrival" of the div; it'll just pop in and out of the screen.
The question: Is there a way to remove the physical dimensions of a div with opacity:0?
In my JSfiddle, you will notice you can get the .iconhover to appear when you hover over the H or e. If you hover over the rest of the word, you're officially hovering over .iconhover and not .wishicon, resulting in the pop-over not showing up.
I hope my question is clear enough.
HTML
<div class="qs">
<div class="wishicon">Hello world</div>
<div class="iconhover">Hovering...</div>
</div>
CSS
.iconhover {
height: auto;
width: 100px;
margin-left:-0px;
color: #fff;
background-color: #666;
box-shadow: 0 1px 0px rgba(0,0,0,1), 0 2px 0px rgba(0,0,0,1), 0 2px 10px rgba(0,0,0,.5);
margin-top:-20px;
margin-left: 20px;
border-radius: 5px;
opacity: 0;
font-size: 12px;
line-height: 1.5em;
font-weight: normal;
transition: opacity 0.5s, margin 0.5s;
-webkit-transition: opacity 0.5s, margin 0.5s;
padding:4px 20px;
text-align: center;
position:absolute;
float: left;
}
.qs > .wishicon:hover + .iconhover {
opacity: 1;
margin-top: -20px;
margin-left: 20px
}
I have a terrific solution which I use often.
On the element with opacity: 0 put pointer-events: none.
It will still have the dimensions, but it will be as if all events are inactive.
Then when you want it to be opacity: 1, return pointer-events to auto.
This is the next best thing to using display: block/none but it can be transitioned!
That would certainly be nice, but alas, I'm not aware of any "ghost" CSS property.
I would treat it the same as a hover menu: make the parent hoverable instead of the previous sibling:
.qs:hover > .iconhover { opacity: 1; ... }

Hover with span and css3

I just created a hover for my menu, but I have a problem with the "span".
I cant't set the width for 100%, so that I will see the all text from the button.
I know that it is possible to set the width rigidly but it should be inherit from the text width.
Can anyone help me with that?
Thanks.
jsfiddle.net/35ufuzw4/
I think you've made this a bit more complex than it needs to be. Here's an updated version of your fiddle:
DEMO
HTML:
Home
About
CSS:
* {
box-sizing: border-box;
}
.navi {
float: left;
text-decoration: none;
position: relative;
color: #000;
font-size: 14px;
padding: 0 20px;
line-height: 40px;
}
.navi:hover {
color: #582d1d;
}
.navi:before {
content: '';
position: absolute;
top: 100%;
left: 0;
right: 0;
bottom: 0;
z-index: -1;
background-color: #000;
-webkit-transition: all 0.4s cubic-bezier(0.05, 0.06, 0.05, 0.95);
transition: all 0.4s cubic-bezier(0.05, 0.06, 0.05, 0.95);
}
.navi:hover:before {
top: 0;
}
Here's how it works:
Instead of using lots of extraneous markup, we keep things semantic using a pseudo element. The ::before pseudo element has position set to absolute, so when its top/left/right/bottom properties are all set to 0, it will be fill the space of the .navi element that has its position set to relative. Setting its top position to 100%, means that we're going to move the top all the way to the bottom. This allows you to set the top to 0 on hover and have the background-color appear to grow from the bottom up.
The .navi class itself is applied to an anchor tag, so since anchor tags are inline, we can float this element and give it some padding left and right. Using line-height, you can control how tall the element is and ensure that the text inside it is vertically aligned in the center. Add a hover pseudo class and you can change its color when the background 'grows' up behind it.