lewisj
lewisj

Reputation: 105

Styling pseudo-elements when a link has wrapped?

I've created an 'underline' animation that uses an ::after pseudo-element underneath the link. Here is the code for the link and the pseudo-element:

Link

a {
    position: relative;
}

::after

a:after {
    content: '';
    display: inline;
    position: absolute;
    height: 2px;
    width: 0%;
    background-color: #ce3f4f;
    left: 0%;
    bottom: 0px;
    transition: all 0.2s ease;
}

a:hover::after {
    width: 100%;
}

This all works fine when the link is on a single line, but if the link flows onto the next line then it only fills across the bottom of the first line, as seen here:

https://i.sstatic.net/7SX7o.jpg

If I inspect the element then it appears that the issue is not solvable, as the browser (in this case, Firefox) isn't selecting the entirety of the wrapped element:

https://i.sstatic.net/342GH.jpg

Is there a way of solving this purely with CSS, or is it a problem with the way the browser renders the objects? I have played around with a lot of white-space, display and position configurations but to no avail.

Here's an example of the behaviour:

https://jsfiddle.net/57Lmkyf4/

Upvotes: 4

Views: 572

Answers (1)

Sidd
Sidd

Reputation: 1397

This cannot be done with CSS. (I've implemented it using JS for links that wrap over not more than 2 lines: https://jsfiddle.net/6zm8L9jq/1/ - you can resize the frame to see it at work)

In my Chrome (39.0.2171.95) the underline under a wrapping a doesn't work at all, while in FF it displays like in your screenshot above. Primarily this is because your a element is inline (default), and when it wraps, any pseudo/child elements that depend on its width get 0 width in Chrome and the element's width on the first row in FF. Inline elements don't have control on their own width/height properties (eg, you can't set a width:100px on them without changing them to block elements), and this also affects any absolutely positioned elements that depend on them for width/height.

If you call the window.getComputedStyle method on the pseudo element in FF and Chrome, like:

var a = document.querySelector('a');
a.onmouseover = function(){

    setTimeout(function(){
        var width = window.getComputedStyle(a,':after').getPropertyValue('width');
        console.log(width);

        },300); //timeout so that animation to 100% width is completed
} 

...in chrome you will see 0px while in FF you will see 100% - and neither will span to actual 100% of the parent. If you added a child element (eg a span) to a instead of a pseudo element, you could investigate the child's actual width after mouseover by calling getBoundingClientRect().width on the child, in which case again, in chrome you would see 0px, and in FF the width of the part of the parent element falling on the first line.

You can change the a element to display: inline-block and it will work, but it will obviously no longer wrap.

Upvotes: 1

Related Questions