Search code examples
javascripthtmlcssfont-awesomefont-awesome-5

FontAwesome 5 Icons with Outlines Not Aligning


I'm trying to prototype a simple "like" button using FontAwesome 5. Clicking it should toggle between a filled red heart icon and an unfilled black border heart icon. The thing is that I want the black border to stay around the heart when it fills. The JS is easy enough, but to create the border, I'm stacking a Regular styled FontAwesome heart on top of a Solid one, yet they're not lining up correctly. I get the red inner heart overflowing the border and spilling out the sides of the outline.

[...document.querySelectorAll('.like')].forEach(heart => {
    heart.addEventListener('click', () => {
        heart.classList.toggle('liked');
        let fill = heart.querySelector('.fill');
        if (heart.classList.contains('liked')) {
            fill.style.opacity = '100%';
        } else {
            fill.style.opacity = '0%';
        }
    });
});
.like {
    display: inline-block;
    cursor: pointer;
    user-select: none;
}
.like > .fill {
    color: red;
    opacity: 0%;
    transition: opacity 0.25s;
}
<script src="https://use.fontawesome.com/releases/v5.0.0/js/all.js"></script>
<div class="like fa-stack">
    <i class="fas fa-heart fa-stack-1x fill"></i>
    <i class="far fa-heart fa-stack-1x border"></i>
</div>

Since FA5 replaces the icons with SVG, things like border and text-shadow don't work. I even tried things like targeting the path element inside and setting its stroke width and color, but I can't fade out the middle like that, and using it with this stack still has misalignment problems.

How do I make a simple bordered heart with FA5 whose solid interior can fade in and out on click?


Solution

  • Instead of stacking, set a stroke on the SVG itself, and toggle the fill color instead of opacity.

    [...document.querySelectorAll('.like')].forEach(heart => {
        heart.addEventListener('click', () => {
            heart.classList.toggle('liked');
        });
    });
    .like {
        display: inline-block;
        cursor: pointer;
        user-select: none;
    }
    .like > .fill {
        color: transparent;
        transition: color 0.25s;
        stroke: black;
        /* The stroke width is huge because the svg itself is ~512x512, which is then scaled down */
        stroke-width: 50px;
    }
    .like.liked > .fill {
        color: red;
    }
    <script src="https://use.fontawesome.com/releases/v5.0.0/js/all.js"></script>
    <div class="like fa-stack">
        <i class="fas fa-heart fa-stack-1x fill"></i>
    </div>