Text underline animation in CSS - the simplest way? - css

I'm having an animated underline effect when user points the links on my website. The underline is a bit wider than the text itself, as there's a bit of horizontal padding.
Here's the effect I wanted to achieve and I did:
I was thinking if it was possible to simplify my code. After some trial and error, I used negative margin-left on the underline element and calc() to calculate its width as 100% + 2 * padding. It looks to me like an overcomplicated solution. Can the same effect be achieved without calc() and, perhaps, without negative margin?
Of note, adding a wrapper element is not an option. It needs to be a plain <a> element.
:root {
--link-color: #f80;
--link-underline-padding: .5em;
}
a {
color: var(--link-color);
display: inline-block;
padding: 0 var(--link-underline-padding);
text-decoration: none;
}
a:after {
background-color: var(--link-color);
content: '';
display: block;
height: .1em;
margin-left: calc(var(--link-underline-padding) * -1);
margin-top: .2em;
transition: width .5s;
width: 0;
}
a:hover:after {
width: calc(100% + var(--link-underline-padding) * 2);
}
I find dogs pretty cool.

A simple background animation can do this:
a {
background: linear-gradient(currentColor 0 0)
bottom left/
var(--underline-width, 0%) 0.1em
no-repeat;
color: #f80;
display: inline-block;
padding: 0 .5em 0.2em;
text-decoration: none;
transition: background-size 0.5s;
}
a:hover {
--underline-width: 100%;
}
I find dogs pretty cool.
Related:
How to animate underline from left to right?
How to hover underline start from center instead of left?

If you set a to position: relative; you can then use position: absolute; and left: 0px; to push it past the padding and then just use width: 100% to have it extend the entire length.
:root {
--link-color: #f80;
--link-underline-padding: .5em;
}
a {
position: relative;
color: var(--link-color);
display: inline-block;
padding: 0px var(--link-underline-padding);
text-decoration: none;
}
a:after {
position: absolute;
left: 0px;
background-color: var(--link-color);
content: '';
display: block;
height: .1em;
margin-top: .2em;
transition: width .5s;
width: 0;
}
a:hover:after {
width: 100%;
}
I find dogs pretty cool.

Related

Changing a span' location depending on different span

Inside my Pen you can see an image block with a title on the bottom. When the user hovers over the block, a description is shown on the bottom and the title is moved.
However, the title is on the correct location if the description contains 1 line of text. With 2 lines of text, the title is on top the description. How could I have the title always just above the description, without moving it all the way to the top of the block?
.trend-block {
position: relative;
width: 150px;
height: 150px;
&:hover {
.transition-title {
bottom: 35px;
}
.trend-text {
display: inline-block;
width: 120px;
color: red;
position: absolute;
bottom: 15px;
padding: 0 15px;
}
}
}
.trend-image {
width: 100%;
height: 100%;
}
.trend-title {
font-weight: bold;
color: red;
position: absolute;
bottom: 15px;
padding: 0 15px;
}
.trend-text {
display: none;
}
.transition-title {
transition: bottom .1s ease;
}
You could make a wrapper class absolute instead of the two spans (.trend-content); https://codepen.io/anon/pen/jxxbpx. The .trend-text does now have a max-height of zero as default. When you hover over it, the max-height will be te same as te container (Can't be a height of auto in order to make the transition).

Create border-bottom smaller than element and with thicker middle

I'm using some stylized HRs to create section separators.
But now I'm trying to create a H1 element with a border bottom smaller than H1 width (variable width according to the width of the H1 text) and with a thicker middle (height).
Something like this:
I scoured several search sources trying to find a solution but found nothing like it.
I tried to use :after and :before but still stuck.
Any idea?
What I've tried so far:
h1 {
display:inline;
border-bottom:1px solid black;
}
h1:after {
content: '';
display: block;
width: 100%;
height: 100%;
border-bottom:3px solid red;
}
<h1>
My Text
</h1>
You can easily do such thing with linear-gradient with no need of extra markup or pseudo element:
h1 {
display:inline-block;
font-size:3em;
padding-bottom:10px;
background:
linear-gradient(red 0 0) 50% calc(100% - 2px)/80% 2px,
linear-gradient(red 0 0) 50% 100% /40% 6px;
background-repeat:no-repeat;
}
<h1>Lorem Ipsum</h1>
You can use the ::before and ::after pseudo elements to create the lines:
h1 {
display:inline-block;
font-size:3em;
position: relative;
font-family: Impact, Arial;
color: #444;
font-weight: 900;
}
h1::before,
h1::after {
content: '';
display: block;
background: #ea596e;
position: absolute;
}
h1::before {
width: 40%;
height: 5px;
bottom: -12px;
left: 30%;
}
h1::after {
width: 80%;
height: 1px;
bottom: -10px;
left: 10%;
}
<h1>my <h1> tag</h1>

Dynamical height of List element brings total Chaos

I want to have some list elements that got a dynamically adjusting height via css.
For better understanding: I am inserting via ::before a number that I count via counter-increment (thats the big ones)
Problem is that nothing that I tried so far brings me even close to what i want to archive. If you change the window size everything gets shoven down...
It should look like this:
I tried:
clear: both; on every element (except the li)
height: auto; on every element
I've already read through some posts but nothing really worked for me.
Dont ask why am I trying to get it done with css... ;)
Thanks for any help!
You have an absolute positioning on your image and thumbnail wrapper which is causing huge problems, look at the adjusted CSS below:
.page-id-3606 .product_thumbnail_wrapper .product_thumbnail a img {
position: relative;
clear: both;
}
.page-id-3606 .product_thumbnail a::before {
counter-increment: section;
content: "0" counter(section) "";
font-size: 10em;
font-weight: bold;
position: relative;
/* top: 100px; */
/* left: 50%; */
line-height: 0;
height: 100px;
width: 100%;
text-align: center !important;
box-sizing: border-box !important;
text-transform: uppercase;
color: #464646;
display: block !important;
border-bottom: 3px solid #464646;
/* transform: translate(-50%, 0); */
margin: 0 !important;
z-index: 10 !important;
}
I fixed it with a little help from Rich.
the missing height and top was causing the trouble:
.page-id-3606 .product_thumbnail_wrapper::before {
content:'';
background: url('...');
height: 130% !important;
width: 100%;
position: absolute;
z-index: 1;
clear: both;
top: -65px;
}

owl carousel navigation hide

I use owl carousel and I want the navigation above the slide in order to navigate easily. Now they are hidden or below the slider. I don't know how to put them above. I tried z-index in the CSS for the carousel and navigation but nothing happens. Need help thank you !
JS
<script>
$(document).ready(function() {
$("#owl-demo2").owlCarousel({
navigation : true, // Show next and prev buttons
slideSpeed : 300,
paginationSpeed : 400,
items : 1,
itemsDesktop : false,
itemsDesktopSmall : false,
itemsTablet: false,
itemsMobile : false
});
});
</script>
CSS
#owl-demo2 .item img{
display: block;
width: 100%;
height: auto;
position: relative;
z-index: 1;
}
.owl-theme .owl-controls .owl-buttons div{
color: #FFF;
display: inline-block;
zoom: 1;
position: fixed;
z-index: 2000;
*display: inline;/*IE7 life-saver */
margin: 90px;
padding: 20px 0px;
font-size: 12px;
-webkit-border-radius: 30px;
-moz-border-radius: 30px;
border-radius: 30px;
background: #869791;
filter: Alpha(Opacity=50);/*IE7 fix*/
opacity: 0.5;
}
.owl-buttons {
position: absolute !important;
top: -45px !important;
left: 50% !important;
transform: translateX(-50%)!important;
}
z-index doesn't put items like you wish it would. I think you need to change positions of these buttons rather than setting different z-index.
Here you have an example of how z-index work. Change z-index as you wish and check how the alignement work on these boxes:
https://jsfiddle.net/grmcfb7z/
You can try this CSS for your solution:
.owl-buttons{
position: absolute;
top: -45px;
left: 50%;
transform: translateX(-50%);
}
You might want to tweak it if it doesn't look as you wish. I tried it on your example from the comments and it looks great to me.
UPDATE
After digging into the exact problem, here is the full solution:
#owl-demo2 .item img {
display: block;
width: 100%;
height: auto; //we don't need position or z-index property here
}
.owl-theme .owl-controls .owl-buttons div {
color: #FFF;
display: inline-block;
zoom: 1;
*display: inline; /*IE7 life-saver */
margin: 10px; //fixed margin to not mess our buttons alignement
padding: 5px 15px; //smaller padding for better look
font-size: 12px;
-webkit-border-radius: 30px;
-moz-border-radius: 30px;
border-radius: 30px;
background: #869791;
filter: Alpha(Opacity=50); /*IE7 fix*/
opacity: 0.5;
}
.owl-buttons, .owl-pagination {
position: absolute !important;
left: 50% !important;
transform: translateX(-50%) !important; //here we override our buttons
//positions
}
.owl-buttons {
top: 0 !important; //nav position
}
.owl-pagination {
bottom: 0 !important; //pagination position
}
Working jsfiddle: https://jsfiddle.net/43wo7g98/3/

Inverse width transition from left to right to right to left

I'm reverse engineering the navigation in http://dreamelectronic.com/ (must use desktop for correct view) but in my own way.
I practically have it down, spot on, but i have one little issue i need to fix to get it just right. what i have is 2 div's that are on top of eachother and they both increase the width of the top border as see in the website. BUT one div starts at the center and stretches from center to the right and the other one stretches from the left to the center (if that makes sense). i need the second div (div2 if you go and read my code from CSSDeck) to start from the center and stretch to the left.
What i have tried is to use transform: rotateX(-180deg); as suggested from one of the answers from another question, i also tried to set the test-align: right; on the div2 also suggested. I tried animation-direction: alternate; too but no cake.
I have come across several similar situations on here but none have worked for me so far.
CSSDeck Project
Many thanks if i can get this last detail down!
You could set the below properties on your div2:
div2 {
float: right;
margin-right: 50px;
...
}
Snippet:
ul {
padding: 0;
margin: 20px;
}
li {
float: left;
list-style: none;
display: inline-block;
width: 100px;
}
div1 {
margin-left: 50px;
text-align: center;
line-height: 3;
display: block;
position: absolute;
width: 0px;
height: 50px;
border-top: 3px solid #D50;
transition: all .4s ease-in-out;
opacity: 0;
}
div2 {
float: right;
margin-right: 50px;
text-align: center;
line-height: 3;
display: block;
width: 0px;
height: 50px;
border-top: 3px solid #D50;
transition: all .4s ease-in-out;
opacity: 0;
}
men a {
text-align: center;
line-height: 3;
color: #444;
text-decoration: none;
display: block;
position: absolute;
width: 100px;
height: 50px;
z-index: 1;
transition: color .4s ease;
margin-top: 4px;
}
men a:hover {
color: #D50;
}
men a:hover~div1 {
width: 50px;
opacity: 1;
}
men a:hover~div2 {
width: 50px;
opacity: 1;
}
<ul>
<li>
<men>
HOME
<div1></div1>
<div2></div2>
</men>
</li>
<li>
<men>
ABOUT
<div1></div1>
<div2></div2>
</men>
</li>
<li>
<men>
PRODUCTS
<div1></div1>
<div2></div2>
</men>
</li>
<li>
<men>
CONTACT
<div1></div1>
<div2></div2>
</men>
</li>
</ul>
So your div1 is pushed using margin-left (which you already had) and your div2 is first forced to float from right and then pushed using margin-right.
Hope this helps.
P.S. Don't forget to close the div2.
You can use positioning for "right-to-left" div:
position: absolute;
right: 0;
http://jsfiddle.net/u5ofdp9m/1/

Resources