Wednesday, February 5, 2014

Create a 1px Horizontal Rule With CSS

Recently I looked into how to create a one pixel black lIne in CSS. CSS has changed the meaning of the <hr> tag. It no longer means what it used to mean!

Instead of being a black horizontal line, an <hr> tag now has a more semantic meaning. It means a major break in the flow of your paragraphs, something like that. Back in the days when <hr> defaulted to being a single black line, the meaning was more visual than semantic.

I want my black line back! Here's how to do it:

hr {
margin: 5px; 
height: 1px; 
border:none; 
color: #000000; 
background-color: #000000;
}

A few notes:

  1. The margin of 5px is because I was working for a client who wanted his horizontal rules to almost touch, but not quite touch, the web design to the left of the horizontal rule and to the right of the horizontal rule. The 5 pixels are to please him. I set the margin to 5 pixels with margin: 5px;
  2. It's weird to me, but it's almost as if under CSS the horizontal rule now has content. Therefore I set the height of this content to 1 pixel. Think of your horizontal line as content and it's easier to conceptualize everything else. At least to me it is. I set my content to 1 pixel with height: 1px;
  3. If you think of your horizontal rule as content, it becomes easier to understand why I've set the border to border: none;
  4. Since a horizontal line is content, I might as well give it the default color of black. I do this with color: #000000;.
  5. To double up on the odds of my content being black, I've also set the background to background-color: #000000;
  6. All this to make a 1 pixel horizontal black line!

There are advantages to the old HTML way of creating a horizontal rule and there are advantages to the new CSS way of doing things.

CSS has the advantage of being a far more flexible model. For this I am grateful. There's nothing more frustrating than being unable to do something you need to do.

However, the old HTML way of doing things has the decided advantage of being easier to discover. I doubt horizontal rules would be as popular as they are today if it were not for the simplicity of the HTML approach. I'm grateful for the fact that I first learned about horizontal rules under HTML. Otherwise, I might never use them.

That said, the CSS approach has the advantage of being simpler once it is set up. If I place the above CSS inside a <style> tag within the <head> tag, a simple unadorned <hr> tag is all I need to implement my horizontal rule. In other words, I can dispense with all the usual <hr> tag attributes.

Each has its advantages!

Here's an example of how you might have coded an <hr> tag prior to HTML being superseded by CSS as the right way to make your web pages pretty:

<hr width="95%" size="1" noshade color="#000000">

It's best not to do things that old way as the old way is far from future-proof. Currently, HTML5 does not support the old way of doing things.

However, if you to research the old way, this page is a good start:

Horizontal Rules With HTML 4.01

Ed Abbott

Sunday, October 6, 2013

Div Background Color Disappears

When using CSS, your background color can sometimes disappear for no obvious reason. Here are 2 possibilities:

  1. Your webpage has been dependent on the hashless hex color quirk.
  2. Your webpage has <div>, or other block content, that consists of nothing but floats

I spent about a month focused on problem #2 above, totally oblivious to the fact that I had problem #1 instead. I wrote about this experience here:

Converting Quirks Mode to Standards Mode

However, I've done so much research into problem #2—the problem with divs that have zero height—that I've decided to catalog all the solutions to this problem known to me.

It's part of the CSS specification that a <div> tag that consists of nothing but floats has zero height by default. In fact, CSS specifies other zero-height boxes as well.

For example, in Section 9.4.2, Inline formatting contexts, the conditions under which a line box can be zero height is described. I quote:

Line boxes that contain no text, no preserved white space, no inline elements with non-zero margins, padding, or borders, and no other in-flow content (such as images, inline blocks or inline tables), and do not end with a preserved newline must be treated as zero-height line boxes for the purposes of determining the positions of any elements inside of them, and must be treated as not existing for any other purpose.

I've added bold-face emphasis to the above quote to emphasize zero height. Here's the original of the quote from the CSS 2.1 specification:

9.4.2 Inline formatting contexts

I count four no's in the above quote. That's a lot of no's. Why all this negation? All these no's suggest to me that a line box that has no content, other than content that is there for the purpose of being positioned elswhere, can only have a height of zero because everything that could be inside the line box is outside the box.

That is to say, the content is outside the box in that the box has zero height. Yet the content is inside the box in terms of where the content starts its positioning from. Kind of a paradox, isn't it?

Whew! When I look at it this way, it makes sense. It makes sense that a line box that is only used as a reference to position things outside itself would have no height.

Likewise, block boxes also have zero height if these same block boxesconsist of nothing but floating elements. Section 10.6.3 of the CSS 2.1 specification describes this as zero otherwise:

10.6.3 Block-level non-replaced elements in normal flow when 'overflow' computes to 'visible'

Zero otherwise? That's not much of a description! The paragraph that follows zero otherwise does a little better:

Only children in the normal flow are taken into account (i.e., floating boxes and absolutely positioned boxes are ignored, and relatively positioned boxes are considered without their offset). Note that the child box may be an anonymous block box.

What the above quite says to me is that a <div> that consists of nothing but floats will have zero height. I realize the above quote is a tough read; however, that's what is says to me.

Can we agree that block boxes that consist of nothing but floats are zero height? If so, then we can move on to the next premise.

The next premise is that there must be a way to make the height of a block box expand to include all its floating children. There is. In fact there are several ways.

Here's a quick summary of 3 different ways I've found in the past month to expand a <div> to include all its floating children in the calculation of its height:

  1. Place an empty <div> after all the floating content and the use the CSS clear property to clear the <div^gt; on both sides
  2. Change the CSS overflow property of the containing block from visible to hidden
  3. The weirdest one of all—use CSS to give the containing block some :after psuedoclass content

I'll start with the weirdest solution first. The uncomfortably weird (to me) :after solution is described in this article:

How To Clear Floats Without Structural Markup

The above article describes solution #3 from my list. Here's a tutorial that describes solutions #1 and 2:

Floats and clearing

I've not tried any of these solutions myself. As I pointed out in the beginning of this post, I've not tried any of these solutions because I've been barking up the wrong tree. I've sought a solution for a problem I did not have.

My motive for writing this post is I wish to document all the research I did rather than lose a month's worth of research.

It's not really a month's worth of research because I was working on many other things at the same time. I call it a month because I've gone back and forth working on this problem, and other problems, for the past month.

The solution I consider the weirdest one, the one that requires you to use the :after pseudo-class, has been updated. You might find this write-up of the solution a little bit more current:

How to use clearfix CSS to clear floats without markup

It's no wonder that the adoption of CSS has been somewhat gradual. Understanding alone can be a problem.

Ed Abbott

Tuesday, June 28, 2011

CSS Link Psuedo-Class Order

I'm forever forgetting what order link
pseudo classes need to appear in. Here's an
article that describes the issue:

Order of Anchor Selectors in CSS

Here's another that describes the same
issue:

CSS Pseudo-classes

OK. I'm starting to see that this is really
just a matter of a few simple rules. Here's
how I see it:

  1. The :link pseudo class should
    come first as this is the most virginal
    of all the pseudo classes. Before a
    link is anything else, it is a link
    and only a link.
  2. Next should come the :visited pseudo
    class. Visited is the next most virginal
    in the sense that a link need only be visited
    once to become a visited link.
  3. The next most virginal of the pseudo
    classes is :hover. Whereas a link can only
    be transformed to a visited link once, a link
    can be transformed via a hover many times.
  4. The least virginal, and therefore the last
    pseudo-class, is the :active pseudo class. The
    :active pseudo class can only become active if
    you press down on your mouse. However, prior
    to pressing on the mouse, you have to get there.
    If you've already gotten there, you have already
    hovered. Therefore, :active is the least virginal
    of all the link psuedo classes

This is all about precedence. You should not
have one psuedo class precede another unless it
actually precedes the other in time.

On the carpet of time, a link is a link before
it is anything else.

Next on the carpet of time, a link becomes an
visited link. While this may not seem right
at first, it is right because the difference
between a link and an visited link is really a
rite of passage. Once the link becomes visited,
it never looks back.

Hence, you really only have two choices for the
initial state of the link. Either the initial
state is :link (colon link) or it is :visited (colon
visited). There are no other initial states for
links. Therefore these two states must follow
each other.

Obviously, :link (colon link) should come before
:visited (colon visited). Obviously a link is
a link before it is a visited link.

The next two states for a link are also fairly
obvious. Prior to pressing the mouse, you must
first hover. Therefore :hover (colon hover) comes
before :active (colon active).

Here's a mnemonic that helps me to remember all
of this:

LVHA

Here's a phrase I use:

Las Vegas Hotel Accommodations

Not a great mnemonic but not too bad either.

To summarize, these two pseudo classes must
come first because they represent a rite of
passage that is never repeated:

  • :link
  • :visited

These two pseudo classes must come second
because they represent transitions that happen
over and over again:

  • :hover
  • :visited

The first transition is a one-time event only.
The second transition happens over and over again.

Once you make the permanent transition come before
the repeating transition, the rest is easy.

I characterize the pseudo classes as interfering
with each other because of a precedence issue.
Actually, it is more of an ovverride issue.

With precedence, one thing takes place before
another. That's part of the issue.

The real issue is that the psuedo-class that
appears last overrides all of the others. When
you use LVHA order, the :active pseudo class
overrides all the other classes if there is a
conflict.

I'm not sure why the pseudo classes come in
conflict with each other. I think of them
as atomic states that should not really be
interfering with each other. The fact that
they do interfere with each other tells me
that I have a ways to go in my understanding.

Ed Abbott