Pseudo element moves from below to above parent on CSS transform - html

I have button with a pseudo element I placed underneath to create a clicking effect. I wrote this code:
button {
appearance: none;
--webkit-appearance: none;
background-color: #0070c9;
border-radius: .3em;
border: none;
color: white;
display: inline-block;
font: inherit;
font-size: 1.5em;
padding: 5px 10px;
position: relative;
text-transform: uppercase;
}
button::after {
background-color: #005496;
border-radius: .3em;
bottom: -.2em;
content: '';
height: 100%;
left: 0;
position: absolute;
width: 100%;
z-index: -1;
}
button:active, button:focus {
outline: none;
}
button:active {
transform: translateY(0.1em);
}
button:active::after {
bottom: -.1em;
}
<button>Button</button>
When the button is clicked, the pseudo element becomes the background of the button; I want the light background to remain over the pseudo element while the transform occurs and after. Is there a reason that the pseudo element moves under the text but above the background of the button?
Note: I am not using any vendor-prefixed CSS in my original code, I just added --webkit-appearance: none; to this page; I will use a post-processor to handle this later.
Edit
The button looks like the left when not in active state, and the the right image in active state.
I do not want the button to become dark when it is in active state. I want the background to remain the same.
I want the button to look like this when it is clicked:

I have added a ::before pseudo element as well and then shifted the z-index of the :before and :after pseudo elements when the button is active. I have also added a span around the buttons text and added a positition of relative and a z-index of 3 to bring it to the front of the pseudo elements.
button {
appearance: none;
background:none;
--webkit-appearance: none;
border-radius: .3em;
border: none;
color: white;
display: inline-block;
font: inherit;
font-size: 1.5em;
padding: 5px 10px;
position: relative;
text-transform: uppercase;
}
button span {
position:relative;
z-index:3;
}
button::before, button::after {
border-radius: .3em;
content: '';
height: 100%;
left: 0;
position: absolute;
width: 100%;
}
button::before {
background-color: #0070c9;
top: 0;
z-index: 2;
}
button::after {
background-color: #005496;
bottom: -.2em;
z-index: 1;
}
button:active, button:focus {
outline: none;
}
button:active span {
bottom: -.2em;
}
button:active::before {
z-index:2;
background:none;
}
button:active::after{
z-index:1;
background-color: #0070c9;
}
<button><span>Button</span></button>

Related

CSS: Skewed button using pseudo position: absolute

I have a button with only a single tag (<a>). I want to skew the background of the button and keep the text as is, so I'm using this code, which is working as expected in my Codepen example:
<a class="et_pb_button et_pb_pricing_table_button" href="#">$200 / Month</a>
.et_pb_pricing_table_button {
margin: 10px;
cursor: pointer;
background-color: transparent;
border: none;
height: 50px;
padding: 10px 60px;
position: relative;
color: #000000;
font-weight: bold;
text-decoration: none;
}
.et_pb_pricing_table_button:after {
z-index: -1;
content: '';
display: block;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
transform: skewX(-15deg);
border-radius: 0px;
background-color: #ffd100;
}
.et_pb_pricing_table_button:hover:after{
background-color: skyblue;
}
However, when I apply that code to my page, it is not rendering as expected (not visible). I can't find anything that is stopping this from working (the parent elements are position: relative). I also tried increasing the z-index of the pseudo selectors, but that didn't help either. What am I missing?

Animating HTML element position on DOM change

I have a list of tags that form a tag cloud. I'll include a search option that will hide/remove the tags that don't match the search. If I do this the tag cloud will rearrange automatically, but it will be instantaneously. I want some form of animation.
I've researched and discovered that the attribute position is not animatable. I've played around with MutationObserver and was able to detect changes in the DOM but was still unsure of what to do on the callback function.
.tagcloud ul {
margin: 0;
padding: 0;
list-style: none;
}
.tagcloud ul li {
position: relative;
display: inline-block;
margin: 0 .75em .5em 0;
padding: 0;
}
.tagcloud ul li a {
position: relative;
display: inline-block;
height: 28px;
line-height: 28px;
padding: 0 1em;
background: #fff;
border: 1px solid #aaa;
border-radius: 3px;
word-wrap: normal;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
color: #333;
font-size: 13px;
text-decoration: none;
-webkit-transition: .2s;
transition: .2s;
}
.tagcloud ul li span {
position: absolute;
top: 0;
right: -10px;
z-index: 2;
width: 28px;
height: 28px;
line-height: 28px;
background-color: #3498db;
border: 1px solid #3498db;
border-radius: 100%;
color: #fff;
font-size: 13px;
text-align: center;
opacity: 0;
-webkit-transition: .2s;
transition: .2s;
-webkit-transform: scale(.4);
transform: scale(.4);
}
.tagcloud ul li span::after {
position: absolute;
top: 50%;
left: -8px;
content: '';
width: 0;
height: 0;
margin-top: -7px;
border-color: transparent #3498db transparent transparent;
border-style: solid;
border-width: 7px 14px 7px 0;
}
.tagcloud ul li a:hover {
border: 1px solid #3498db;
color: #3498db;
}
.tagcloud ul li:hover span {
right: -26px;
opacity: 1;
-webkit-transform: scale(1);
transform: scale(1);
}
<div class="tagcloud">
<ul>
<li>javascript<span>10</span></li>
<li>android<span>6</span></li>
<li>c++<span>20</span></li>
<li>c<span>15</span></li>
<li>java<span>16</span></li>
<li>html<span>4</span></li>
<li>css<span>11</span></li>
<li>python<span>17</span></li>
<li>artificial intelligence<span>5</span></li>
<li>computer graphics<span>9</span></li>
<li>php<span>8</span></li>
<li>computer audio<span>7</span></li>
<li>database<span>7</span></li>
<li>web<span>12</span></li>
<li>sql<span>6</span></li>
</ul>
</div>
This might not answer your question directly because in my opinion hiding element is a lot easier than remove it (or wait it removed).
After input event triggered, for each element we need to determine to do some animations or ignore it. In case of do animation we need to determine more between 2 animations which are exit animation (animate element then hide it) and entry animtion (show element then animate it).
input.addEventListener('input', event => {
let re = new RegExp(input.value)
ul.querySelectorAll('li').forEach(li => {
let isHidden = li.style.display === 'none'
let shouldHide = !re.test(li.textContent)
if (shouldHide && !isHidden) {
// Play exit animation
}
if (!shouldHide && isHidden) {
// Play entry animation
}
})
})
I suggest to use javascript animation library (in example I use animejs) to handle animation instead of pure css animation because we need to toggle display which not working on pure css.
See full example here.
I hope this help. Thanks.

Overlap ::after and ::before with text in CSS

Goal: Make nice effect of hovering buttons in pure CSS, which will use ::after and ::before pseudo-elements. Look at this jsFiddle example to see, what I want to reach.
Code: Button will have some styling, also an background-color, which is turned off in this example.
.button {
display: inline-block;
position: relative;
height: 35px;
line-height: 35px;
padding: 0 15px;
/*background-color: white;*/
text-decoration: none;
color: black;
}
Problem: I want to use background-color and when I enable it, then I can't see pseudo-elements. It is like that, because these pseudo-elements have z-index: -1;, which put them behind the background. When I change z-index to 0 or 1, then text is not visible.
What I can't do: I can't add new elements inside buttons (like spans), because this is one already running website and client decided to change the behavior of buttons, so here I am. There are tons of buttons in this website, so this is the reason, why I want to find solution with pseudo-elements, because trying to find every single button and change them would be inappropriate.
If i understood you well, this is what you are looking for:
.button {
display: inline-block;
position: relative;
height: 35px;
line-height: 35px;
padding: 0 15px;
/*background-color: white;*/
text-decoration: none;
color: black;
border:1px solid;
}
a.button:before {
content: " ";
display: block;
z-index: -1;
position: absolute;
height: 0%;
top: 0;
right: 0;
left: 0;
background: #ddd;
transition: height 0.2s ease;
}
a.button:hover:before {
height:100%;
}
TEST
Consider an alternative method of doing the background colour transition thing.
As seen in this edited demo:
/* remove all references to .button::before */
.button {
background-image: linear-gradient(to bottom,
transparent, transparent 100%,
red 100%, red);
transition: background-image 0.5s ease 0s;
}
/* the "gradient" above has the practical result of being fully transparent,
but it has been carefully crafted so that the transition gives the desired result */
.button:hover {
background-image: linear-gradient(to bottom,
transparent, transparent 0%,
red 0%, red);
}
You can transition gadients, and in this case it is done stop-by-stop. The first and last stops don't change, but the middle two transition from 100% to 0%, essentially meaning that the cut-off point between transparent and red slides from the bottom to the top of the button, giving the effect you want.
You can now replace transparent with your desired background colour.
* You may need to remove the z-index:-1 from the ::after element to get the border effect back.
You can do something like,
HTML
CSS
body {
background: #FF7272;
}
.button {
display: inline-block;
position: relative;
height: 35px;
line-height: 35px;
padding: 0 15px;
text-decoration: none;
color: black;
z-index: 0;
background-color: white;
width: 50px;
}
.button::before, .button::after {
content: '';
position: absolute;
left: 0;
right: 0;
bottom: 0;
}
.button::after {
content: "TEST";
height: 50%;
width: 72px;
text-align: center;
z-index: 2;
line-height: 0.2;
border-left: 4px solid red;
border-right: 4px solid red;
border-bottom: 4px solid red;
}
.button::before {
height: 0%;
background-color: red;
transition: all 0.5s ease 0s;
z-index: 1;
}
.button:hover::before {
height: 100%;
}
Example: https://jsfiddle.net/LL0f7rwp/6/
Some values are hard coded, but hope you can get an idea out of it :)
It's because z-index: -1 and background-color: white will push your :before and :after elements beneath.
Remove z-index: -1 from :after and :before and add to hover .button:hover::before
Make the background-color: transparent while hovering. Updated fiddle.
body {
background: #FF7272;
}
.button {
display: inline-block;
position: relative;
height: 35px;
line-height: 35px;
padding: 0 15px;
background-color: white;
text-decoration: none;
color: black;
}
.button::before,
.button::after {
content: '';
position: absolute;
left: 0;
right: 0;
bottom: 0;
}
.button::after {
height: 50%;
border: 4px solid red;
border-top: 0;
}
.button::before {
height: 0%;
background-color: red;
transition: all 0.5s ease 0s;
}
.button:hover::before {
height: 100%;
z-index: -1;
}
.button:hover {
background-color: transparent;
}
TEST

:before element overlapping my button text on hover

I have a button with a background color, and text color set. What I like to do, is when the user hover the mouse on the button, the background to animate from bottom to top and change the color of the text to the color of the background.
For terms of simplicity of the code, I didn't put the transient I like to apply on the CSS properties. I know it's much easyer to change the button background code, but I plan to use transient for changing the :before height on hover.
So I have the following code, but when I hover the mouse on the button, the :before overlapping my button text.
I have also try to play with the z-index but no luck. Do you think is there any solution to this problem ?
body {
background: #111;
}
.btn {
color: #FFF;
background: #333;
border: none;
font-size: 18px;
font-weight: bold;
padding: 18px 60px;
position: relative;
}
.btn:before {
display: block;
content: '';
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 0;
background: #FFF;
}
.btn:hover {
color: #333;
}
.btn:hover:before {
height: 100%;
}
<br />
Do Stuff
You need to add additional <span> element which would stay above the ::before pseudoelement:
span {
position: relative;
z-index: 1;
}
fiddle
The effect you desire can also be achieved without adding the additional span. By utilising the before and after pseudo elements for background colours and positioning them correctly.
To position the pseudo elements behind the text, set a positive z-index on the element and a negative z-index on the pseudo-element.
.btn {z-index: 1}
.btn:before {z-index: -1;}
Reference this article by Nicolas Gallagher which explains in more detail, see section 'Pseudo background-position' http://nicolasgallagher.com/an-introduction-to-css-pseudo-element-hacks/.
Also see fiddle with it in action: https://jsfiddle.net/j9whmcmz/2/
This technique does not work if you apply a background color to the .btn itself.
Choose your poison I guess, both solutions do the trick.
Try this:
body {
background: #333;
}
.btn {
color: #FFF;
background: #333;
display: inline-block;
position: relative;
overflow: hidden;
-webkit-transition: color 0.3s ease-in-out;
transition: color 0.3s ease-in-out;
}
.btn span {
display: inline-block;
padding: 18px 60px;
border: none;
font-size: 18px;
font-weight: bold;
z-index: 10;
position: relative;
}
.btn:after {
display: block;
content: '';
position: absolute;
top: 100%;
left: 0;
width: 100%;
max-height: 0;
background: #FFF;
height: 100%;
z-index: 9;
-webkit-transition: all 0.3s ease-in-out;
transition: all 0.3s ease-in-out;
}
.btn:hover {
color: #333;
}
.btn:hover:after {
max-height: 100%;
top: 0;
}
<span>Do Stuff</span>
Solution if pretty obvious - content of the button should be also absolute positioned. Then browser order them properly behind each other.
EDIT: Maybe my formatting and styling is not the best for the case, but it was quick update of your code to get the idea
body {
background: #111;
}
.btn {
color: #FFF;
background: #333;
border: none;
font-size: 18px;
font-weight: bold;
padding: 18px 60px;
position: relative;
}
.btn span {
display: block;
content: '';
position: absolute;
top: 18px;
left: 0px;
width: 100%;
text-align: center;
}
.btn:before {
display: block;
content: '';
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 0;
background: #FFF;
}
.btn:hover {
color: #333;
}
.btn:hover:before {
height: 100%;
}
<br />
<span>Do Stuff</span>

Tooltip is showing when hover on black space

http://fiddle.jshell.net/9m6a5y5p/
As you can is in demo above, when hover above span element tooltip is shown and i want only to show when hover on span... Yes I know i can use display: none, but i am trying to avoid that...
tooltip {
color: #E4095C;
position: relative;
}
.tooltip::before,
.tooltip::after {
opacity: 0;
z-index: -100;
position: absolute;
}
.tooltip:hover::before,
.tooltip:hover::after {
opacity: 1;
z-index: 100;
}
.tooltip::before {
content: '';
border: .825em solid transparent;
border-top-color: #0D8EAD;
bottom: 45%;
left: 35%;
}
.tooltip::after {
content: attr(data-tip);
width: 12em;
padding: .85em;
background: #0D8EAD;
bottom: 175%;
left: 5%;
margin-left: -3.25em;
color: #f8f8f8;
}
Just add following css after .tooltip::after{}
.tooltip::after {
pointer-events: none;
}
Have fun..!!
You can use pointer-events to prevent hover events from firing. Add this to your CSS:
.tooltip::after {
pointer-events: none;
}