The link at the top of this page is a plain-jane, run-of-the-mill, vanilla, nothing-special link. But it can be so much more! Let's turn it into something to write home about!
To get started, let's use a bit of positioning to keep that link visible on the page where we can see it as we continue working through this exercise.
header
element, with the following rules:position: fixed;
top: 0;
left: 0;
width: 100%;
height: 200px;
background: #000;
This made a fixed page header, but it's covering our page content. We can fix that.
body
element, and set padding-top
to be the same as our header
height.Now let's center the link in our page header. Instead of using padding or margin to push the link around, let's use absolute positioning. This link is not going to be styled like a standard link, so probably best if we give it a class, rather than just selecting by tag name.
class="launch-button"
to the a
element..launch-button
. Add the following styles:position: absolute;
left: 50%;
top: 50%;
The link is now in the middle of the header... sorta. It's actually riding a bit low and right, because we haven't actually positioned the link's center, we've positioned it's left and top edges. For the link to be truly centered, we need to offset back toward the top by half the link's height, and toward the left by half the link's width. We could try to measure the link and do the math, but it makes more sense to have the browser do the math for us. We'll do so by using a new css property: transform
. The transform
property is used to visually transform an element by skewing, rotating, scaling, and/or translating (moving).
.launch-button
selector:transform: translate(-50%, -50%);
(The two numbers correspond to horizontal and vertical.)The link is now exactly centered... even though we don't know the exact width of either the header or the link itself. It's a useful technique for centering an absolutely-positioned item in its container.
This approach may seem a bit counter-intuitive, because it looks like we asked the link to shift left by 50%, then back right by 50%. So why didn't it go back to it's starting position? The answer is that when we use a percentage as a unit for positioning we're referring to a percentage of the parent container. For transform, on the other hand, percentages refer to the element being transformed. So what we're really doing here is saying "Move from the left side half the width of the header, (left: 50%;
) then move back by half the width of the link ( transform: translate(-50%, -50);
). Similarly, move down from the top by 50% the height of the header, then back up by half the height of the link.
The link has been located in our 'hero' position... time to style it.
Let's get rid of some default 'link' styles, and add some 'button' styles.
.launch-button
ruleset, add:text-decoration: none;
background-color: #aa0000;
color: white;
font-size: 20px;
padding: 15px 30px;
border-radius: 10px;
No surprises here, we've used all these properties before. Let's reinforce the interactive nature of the button by giving it a :hover
state and :active
state.
.launch-button:hover
. Add:background-color: #cc0000;
box-shadow: 0 0 8px #ff0000;
.launch-button:active
. Add:background-color: #750000;
box-shadow: 0 0 2px #750000;
The box-shadow property is one you may not have used. It's very flexible, and can make all kinds of shadows/glows. You can read the docs to learn more, or you can use a box-shadow generator.
Our button now has a fun glow when we hover, and darkens when pressed. It feels like a button... but maybe not a very exciting one.
We've used font-awesome before to add icons. We'll use it here as well... and we're going to use the transform
property to have some fun with them. This page already has the font-awesome library added in the head
, so we're good to go.
a class="launch-button"
element here in the html page, on a line right after the word "launch" but before the closing /a
tag, add the following html:
<div class="rocket">
<i class="fas fa-burn"></i>
<i class="fas fa-rocket"></i>
</div>
The i
tag normally italicizes text, but font-awesome has appropriated it for adding icons. We've added two icons: "burn" and "rocket."
Now, let's put these icons where we want them to go. I'd like to have the rocket sitting to the right of the text, pointing straight up, with the flame coming out the bottom. The div class="rocket"
container will serve as a positioning parent for the icons, and the container itself will also be positioned within the button.
.launch-button .rocket
and set:position: absolute;
This makes it a positioning parent for its descendant elements, in this case, the icons..launch-button .rocket i
, which selects both icons. Set:position: absolute;
top: 0;
left: 0;
The icons are now smashed together in the .rocket
container, absolutely-positioned in the same place. Now let's use transform
to arrange them the way we want.
.launch-button .fa-rocket
and set transform: translate(-50%, -50%) rotate(-45deg);
. This centers the rocket in its container (just like we did the button in the header), and rotates it to point straight up..launch-button .fa-burn
and set transform: translate(-50%, -15%) rotate(180deg) scale(0.3);
. This centers it horizontally, aligning it with the rocket, but leaves it hanging lower vertically, so it's toward the rocket exhaust nozzle. It also rotates it 180°, and makes it smaller.The overall rocket is still in the wrong position. Let's make room for it to live next to the button text using padding, then position it in the space we make.
.launch-button
ruleset, change padding
to 15px 60px 15px 30px;
. We're opening a space on the button's right side..launch-button .rocket
ruleset, add:top: 50%;
Centers the rocket vertically.right: 40px;
Positions the rocket 40px from the right edge, in the gap we made.The flame gets a bit lost, let's use color!
.launch-button .fa-burn
ruleset add color: orange;
.Seems like the rocket should have some interaction on :hover
and :active
too, doesn't it? Let's progressively increase engine power as we approach launch!
.launch-button .fa-burn
, change the value for scale
to 0.1
. The booster will be 'off' by default..launch-button:hover .fa-burn
. Note how this selector works. It's saying "Select elements with the .fa-burn
class that are inside of a hovered .launch-button
. So even though we're styling the flame, this ruleset will be applied when the button is hovered, not the flame icon itself.transform: translate(-50%, -15%) rotate(180deg) scale(0.4);
. We're overriding the default transform to make the flame bigger on hover..launch-button:active .fa-burn
, and set transform: translate(-50%, 25%) rotate(180deg) scale(0.8);
. We're overriding to make the flame still bigger on active. We're also shifting it downward so the whole flame is exposed.Seems like the whole rocket could also get bigger on hover, to make it pop a bit. We'll scale the container that holds both icons, treating our rocket arrangement as a single element.
.launch-button:hover .rocket
to select the .rocket
container when the button is hovered. Add transform: scale(1.3);
.Could we? Make the rocket actually launch? I think we can!
First, let's create an environment to launch into, using a linear-gradient background.
background
with background: linear-gradient(to bottom, #000000 40%,#0560aa 80%,#7cd4ef 100%);
.I used The Colorzilla Gradient Generator to make it easy.
Now, when the button is active, let's push the button back and bring the rocket up and forward.
.launch-button
change top
to 75%
. We're moving the whole button downward to make room for it to launch above..launch-button:active
ruleset, add transform: translate(-50%, -20%) scale(0.7);
. We're pushing the button down and scaling it way back when active..launch-button:active .rocket
ruleset to select the rocket, and add transform: rotate(-15deg) translate(60px, -140px) scale(3.5);
. We're launching the rocket away from the button.That's pretty fun! I feel like the label of the button is a little plain though, and it's strange that there's still a gap next to it where the rocket was. Let's clean it up. We'll start by adding a span
around the word "Launch" so we can style it safely without affecting the icon style.
Launch
becomes <span class="label">Launch</span>
.letter-spacing: 0.1em;
text-transform: uppercase;
color: white;
color: orange;
text-shadow: 0 0 3px rgb(251, 255, 0, 0.5);
.launch-button:active
ruleset, add padding: 15px 30px;
to take away the gap when the rocket is safely away.Note the text-shadow
? It's similar to box-shadow
, but for text. Here's a useful generator.
What's really going to send this thing over the moon (sorry, I'm a dad) is transitioning from one state to the next, instead of just 'jumping' from default to hover to active. CSS lets us do that with the transition
property. Strap yourself in. (I'm on fire!)
.launch-button
ruleset, add transition: transform 0.5s, background-color 0.1s, padding 0.5s, box-shadow 0.1s;
. Note how we are giving a list of properties to transition, each with a duration. So padding
, for instance, will transition over 0.5 seconds..launch-button .rocket
ruleset, add transition: transform 0.5s;
..launch-button .label
selector, add transition: color 0.2s, text-shadow 0.2s;
..launch-button .fa-burn
selector, add transition: transform 0.4s;
.Press the button and marvel at what you have made!
You might think we're done... you might want to be done... but no, we have one final area to explore. Transitions are great, but what if you want an animation to keep going?
@keyframes burn {
from { transform: rotate(-7deg); }
33% { transform: rotate(4deg); }
66% { transform: rotate(-4deg); }
to { transform: rotate(7deg); }
}
We've just added a set of keyframes with the name burn. The keyframes define a series of changes to a property or set of properties. But if you look at the page, you won't see any change yet. That's because we have not applied these keyframes to any element.
I want to apply them to our flame icon, to give it a 'shaking' effect. However, the flame already has a transform
on it, and I don't want to mess with that. The inspector reveals, however, that the actual icon is in a ::before
element, because that's how font-awesome does it, which means I can style the ::before
element without changing anything about the i
tag that contains it.
So let's apply this animation.
.launch-button:active .fa-burn::before
ruleset, and add:display: block;
Not sure why, but needs this to animate.transform-origin: center bottom;
This means "apply the transform around an axis at the base of the flame, not the center of it."animation-name: burn;
This tells the element that it should use the "burn" keyframes.animation-duration: 0.1s;
Specifies the time over which a single 'loop' of the keyframes should span.animation-iteration-count: infinite;
This tells the animation to loop without end (as long as this selector applies).animation-direction: alternate;
This tells the keyframes to alternate forward and backward in time, 'bouncing' back and forth.As you appreciate what you've made, be sure to make appropriate rocket-booster noises with your mouth.
Our mission is complete. In the process of styling this button we've introduced linear gradients, box shadows, text-shadows, transforms, transitions, and animations. It's as far as I will take you for now, but know that each of these things has tremendous capability and flexibility, and you should treat this as only a single example of how and where they might be applied. While we used them for a button, there's nothing that says they can't be used elsewhere, and in infinite combinations. Explore!