Greased Issues

Issue #15.1C November 6th, 2015 Volume 1
 

Azure
Edition

Greased: The Nerd Bacon Newsletter (Logo)


Greased 1.15.1C - Advanced CSS Explained

November 6th, 2015

Difficulty: 6

EasyDifficult

Alright, ready to move into the really heavy stuff? This is as tough as it gets. I know I took a big leap from a simple horizontal list to a full-fledged menu, and although this is a far cry from a crash course in CSS, hopefully it'll explain each and every element and exactly how it was done. Let's get to it.


<style>
This is the opening tag for an internal style sheet, very similar to how we add style within some HTML elements such as <li style="float: left;">. In fact, when you see style like that within an HTML element, it means we're moving into inline CSS instead of HTML proper.

ul.nav {
Here I'm creating a class for <ul> called "nav" which the following rules will apply to.

list-style-type: none;
We went over this a bunch; it gets rid of the bullets!

margin: 0;
Gets rid of any default extraneous spacing in our list so that it can "fit together" horizotally.

padding: 0;
Same as above!

overflow: hidden;
A weird trick that no one can explain. It somehow keeps the ul block from collapsing on itself. 100% necessary.

width: 485px;
Normally ul fills the entire width of its parent area, regardless of the actual length of content. However, if we can give it a fixed width, we can then center it. This is calculated by adding up the widths of all the lis that comprise it plus any borders, margins, or padding applied to those lis.

margin-left: auto;
CSS can be kind of weird sometimes, and believe it or not, this combined with the following declaration is the "best" way to horizontally center something.

margin-right: auto;
See above!

border: groove 3px black;
}

Standard border declaration; groove refers to the style of border, 3px denotes the thickness, and the color is defined by black.

ul.nav li {
Now we've moved on to a new declaration block. This is saying that the following rules will be applied to any li elements appearing within a "nav" class ul.

float: left;
This puts our block elements (li) into a neat line instead of the default, which is one block element per line. (Or more correctly, block elements take up the entire width of their parent container regardless of the width of the actual content, meaning nothing can appear "beside" them under default conditions.)

width: 80px;
Specifies the exact width of an object.

text-align: center;
Centers the text within each li block.

text-shadow: 2px 2px black;
A fun little decoration; the first number determines the horizontal offset of the shadow, the second number equals the vertical offset, and black specifies the color.

font-weight: bold;
This is how we embolden in CSS!

border-right: solid 1px #000;
}

Standard border definition, this time just for the right side. This is what creates the thin dividers between each "button." We could be lazy and leave the last button with a useless border-right as well, but if we do, our rightmost border for the ul as a whole will appear 1px larger than the top, bottom, and left sides. The next declaration block will "fix" this. Yes, this is nitpicky, but I wanted to throw in at least one nitpicky situation since CSS is all about nitpicking. In fact, maybe we'll look at an example where these dividers are a different color than the larger border where the difference can truly be illustrated.

ul.nav li.end {
Now we're starting another declaration block, with these rules applying to any li class "end" within any ul class "nav." This is where things can get a little confusing. Even though this li has a class of "end," it's still subject to the rules of all li within ul class "nav" as well. I created this one because I want any li class "end" to follow additional roles that I don't necessarily want to apply to li in general within ul class "nav."

border-right: 0 !important;
}

In this case, I'm saying that in addition to all the rules laid out for li in ul class "nav," I want li class "end" to have the property border-right: 0;. But wait, those li already have border-right: solid 1px #000;, so how can they have border-right: 0; as well!? There are a few inherent rules in CSS to deal with seemingly contradicting declarations (and honestly they confuse me from time to time) and this is a good example of at least one of those rules in play. If you've been keeping up, you'll see that we have a conflict here: all li tags under ul class "nav" should have border-right: solid 1px #000;, yet this rule says that those li class "end" have no border. I'm pretty sure that the specificity rule kicks in here, and since an li with a class is more specific than an li without one, this rule takes precedence. CSS also adheres to rule order, meaning that later rules trump earlier ones. So if specificity didn't apply, this would still work because it comes later in the document. Luckily, even when these get confusing, we can make sure that the rule takes precedence by setting the !important annotation, which overrides both specificity and rule order. If specificity is the applicable rule here (and I think it is based on some cursory testing), then it doesn't matter where the rule appears or if the !important annotation is included or not. But like I said, I wanted to throw in something tricky just to show you how complicated this stuff can get, even when it comes down to a simple 1px line.

I should probably warn you though, it is best to learn something about these rules if you plan on a lot of possibly contradictary statements and not to lean too very heavily on !important. Most of the time inline CSS will override anything in an internal or external style sheet, so if you ever do need to make a quick exception or deviation from the norm you can do so without having to write an entirely new rule or class (and if I'm being 100% truthful, that's probably the route I should've taken here: a quick inline change to that last li, though what I've done here might be worth it if I were putting menus like this on many pages). However, the problem with !important is that nothing can override it! Not rule order, not specificity, and not even inline CSS can do a damn thing to stop the mighty !important. It takes absolute priority. If you are going to use it, be sure to give yourself an "out." For example, if I use something like p {color: green !important;} in an internal or external style sheet, every bit of text within <p> tags will be green, always. Try to use <p style="color: red;">? Nope. Won't work. And get this, even if, within the same style sheet, you create a rule like p.colorOrange {color: orange;} (that's saying any p with the class "colorOrange" will have orange text) and use <p class="colorOrange"> in the document itself, the text will remain green. That's how powerful it is. And yet, if you had to, you could get around it all by using inline CSS within the span tag...I was close to launching into a full-blown example, but I'm getting way ahead of myself. Just remember that nothing overrides !important, though that's not to say you can't get around it...such is CSS.

ul.nav a:link, ul.nav a:visited {
Here's where we start getting into those pseudoclasses that can't be used with inline CSS. We can control a:link with inline stuff, but not the rest. These rules will apply to links both visited and unvisited that appear within a ul class "nav."

background: #800080;
All we're doing here is setting the background for the linked text.

display: block;
Now we're making these links appear as blocks, which makes the whole area clickable and not just the text. This gives our menu that "button-y" feel.

padding: 5px;
}

This one is a little bit tricky, mostly because the effect isn't immediately obvious. This refers to the padding of the link itself - normally it would extend the clickable area, except that doesn't matter since we've defined these links as block elements and they're already taking up the entire width available. Horizontally, the padding simply extends into space already accounted for by the fixed width of li (which the link is forced to fill as a block element). However, it also adds 5px worth of padding to the top and bottom of the link as well, uniformly increasing the height of these areas, and giving the buttons a fuller appearance. This is a neat (but not immediately obvious) trick for adding a little bit of height to the "buttons." If you simply try to increase the height of lis, the text won't be vertically centered and the block property of the link won't cover it (remember, blocks take up the entire width available, not height). Likewise we could perhaps add padding to the li, except this will actually act as a buffer between the li box and the link within. So bumping up the padding of the links becomes a useful albeit convoluted trick. Since the padding is part of the link itself it stays clickable and retains the link's properties (such as the color).

Special Note: Not Included in Original CSS
color: #03a89e;
text-decoration: none;

These 2 declarations are not included in the original style sheet I wrote, but if you were to attempt to replicate my menu to a tee, you would need to add these to the above declaration block. This is because these 2 properties are defined in the external style sheet that governs the newsletters. I probably should've changed these to better illustrate what's possible, but it's just a couple of small details. What these say is that links, both visited and unvisited, will appear as color #03a89e and that they will not appear underlined. Links, by default, appear underlined, but text-decoration: none; takes care of that. Note that even though I have a:link and a:visited lumped together, different values for each can be used to an extent. There's infinite flexibility when it comes to a:link, and a:visited will inherit these properties, but there are very few properties allowed in a:visited due to security reasons.

ul.nav a:hover, ul.nav a:active {
This declaration block is similar to the previous one, only now we're defining (within ul class "nav") what links look like when the cursor is held over them and what links look like the moment they're clicked upon. (Just for fun, :active and :hover can be used for elements other than links!) In most instances, these 2 are lumped together since :active is only visible for a the duration of a click. However, having a link - and especially a whole are ("button") like we're working with now - change appearance when hovered over can make the menu feel more lively and "button-like." Both :hover and :active are pseudoclasses, meaning they cannot be defined with inline CSS, therefore requiring an internal or external style sheet.

background: #ff809f;
This defines what color the background of the linked text will appear when hovered over (within a ul of the class "nav" of course).

color: black;
Defines the color of the linked text when hovered over.

text-shadow: none;
No text-shadow will appear when the link text is hovered over. Normally this wouldn't be necessary, except we included a text-shadow previously for linked text. We don't need to "turn it off" either, I just decided to do away with it in order to maximize the contrast between the "buttons" when hovered over.

font-style: italic;
This makes the link text appear in italics when hovered; again, I did this to maximize contrast between hovered and "unhovered" buttons on the menu.

font-variant: small-caps;
Turns the linked text into small-caps when hovered. Done for contrast!

text-decoration: none;
}

By default, all aspects of a (:link, :visited, :hover, and :active) are set to text-decoration: underline;. Whether or not you'll actually need this declaration to get rid of underlined links will depend more immediately on the specifications of the external style sheet (as may other elements you work with). It's important to remember that that if you're doing something like this for NB (or any site for that matter), you're not starting from a blank slate. You'll have to account for the site's external style sheet as well. For instance, what if a site had all of their text rendered in uppercase (by using something like body {text-transform: uppercase;} in their CSS) and you wanted to do something simple like make list items appear blue (and maintain control of your own capitalization)? Normally li {color: blue;} would be good enough since text is not transformed into uppercase by default, but since the site's external CSS is capitalizing all text, you're going to have to use li {color: blue; text-transform: none;} to "undo" this aspect. Quite often I'll be playing around with some CSS and then when I move it over to Nerd Bacon I'm shocked at how strangely it turns out!

</style>
That's it! We're closing the style tag and wrapping things up!


I think that pretty much covers all the CSS that went into the "fancy" menu. I should probably stop here; before I know it we'll be knee deep in CSS experiments and menus made out of horizontal lists will be the last thing on your mind the next time you feel adventurous. There is one last thing though. Earlier when I was talking about how tricky CSS can be in our situations with borders, I said I'd show you just what things looked like if we had different colored borders. First let's look at the original "fancy" menu to see how things "should" look. Remember that my intention was to create divisions between each link/box to give them a more "menu-y" or "button-like" appearance. That was pretty easy; the tricky part was how to handle that last item that didn't need a border to the right.

Alright, that's how it should look, ideally. Each of the first 5 list items has a border on the right of 1px in thickness. Since the sixth one has the border of the entire ul on the right, it doesn't really need the border on the right. However, since styling all the list items at once is the easiest thing to do (and indeed part of the point of separating CSS and HTML in the first place), it might be tempting not to worry about that last item and just let that right border appear anyway. After all, it'll just blend in with the larger ul border, thought it will make it a single pixel thicker than the borders on the top, bottom, and left. Maybe you're thinking you could compensate by making the top, bottom, and left borders 1px thicker? Not a bad idea, except that extra pixel will appear on the outside, (borders and margins manifest on the outside of elements while padding is on the inside) and the extra pixel from the list item is coming in from the right. If you're trying to keep things simple, you'll probably just learn to live with that extra pixel and move along. And hey, no one would blame you. It may not be ideal, but it ain't wrong. Again, I just want to illustrate how interesting CSS can get. If you did decide to let that extra pixel go, here's what the final product would look like:

Not a big deal, but I can tell that the right edge is thicker - moreover when hovering over "Indigo" and changing the background to pink, I can plainly see that the right border is thicker than the adjoining top and bottom sections. But again, it's one tiny pixel. It would be even less obvious were the outer border were a little thicker; it's only 3px wide anyway, so adding another 1px is causing a 33% increase in size. If you're just starting to play with these things, it might be better to leave it alone and be proud of all that you have already accomplished instead of giving yourself a headache over this sort of minutiae. Then again, it's easy to get caught up seeking perfection.

The only real problem I can foresee is if you wanted to use a different color for the dividers than the outer border. The severity of the discrepancy will depend on the contrast between the 2 colors used, for example gray dividers and a white outer border wouldn't prove too noticeable. But what if we did something totally crazy, like a purple border and yellow dividers? Let's see what that looks like! For the sake of illustration, I'm going to change the purple background of those buttons to black so we don't have too many colors floating around. Let's give it a shot!

Now that tiny little line is a bit more obvious. I didn't change anything structurally, just the colors. Of course this is an extreme example to prove a point, and yet it also illustrates how problems and issues can arise in CSS. If you'd kept the border and the dividers black, you may not have even noticed that something was amiss. But after a quick color change, this minor flaw becomes obvious and looks exactly what it is - one of those dividers tacked on when it doesn't need to be.

But enough of that...and enough of this...until next time at least! After all, we want you guys writing reviews, not necessarily becoming coding experts (although technically speaking none of this (neither CSS nor HTML) is "code"), but if this spurs your interest then so be it! It definitely wouldn't hurt to have another committed member who knows a thing about web design. This auxiliary document may have been a little (or a lot) outside of what I originally intended to show you, and even if you don't pick up on every bit of nuance, I hope you at least have the courage and basic know-how to put together a horizontal list and make it look like a menu. If you really are interested, I'll be glad to help you out! Take a crack at it yourself first, and then come to me with what you've got, what your problems are, and what you'd like to get out of the finished result. And finally, be sure to take a look at doing it with tables for a completely different setup. If you've made it this far, I think you'll find both the similarities and differences fairly interesting.

Good luck!


Doing It with Tables


Example Variations


NerdBerry
NerdBerry@NerdBacon.com
The Cubist
TheCubist@NerdBacon.com
Doc Croc
DocCroc@NerdBacon.com
 
Issue #15.1C November 6th, 2015 Volume 1