
In a recently published and controversial
article,
it was claimed that "Full
CSS Site[s] TEND to be very BOXY look'n and sharp
edges ....translation: ‘No
rounded corners’.
This is because it get tedious to place the rounded
corners and match them up to the outer box".
We respectfully disagree, and do so by showing how
easy it actually is. We'll even take it a step further,
and show how customized borders and corners can be
applied to fully fluid and flexible layouts with dynamic
content, using what we consider to be sound and semantically
logical markup.
Here is what we got:
<h3>Article header</h3> <p> A few paragraphs of article text.<br /> A few paragraphs of article text. </p> <p> A few paragraphs of article text.<br /> A few paragraphs of article text. </p> <p> A paragraph containing author information </p>
If we want full control of the layout, we need to
make sure we have enough elements we can
target with our CSS. Let's call these elements "hooks". Our
markup needs just a few more.
First of all, let's wrap the whole article in a containg
div, and then wrap each structural section in an
element also:
<div class="Article"> <h3>Article header</h3> <div class="ArticleBody"> <p> A few paragraphs of article text.<br /> A few paragraphs of article text. </p> <p> A few paragraphs of article text.<br /> A few paragraphs of article text. </p> </div> <div class="ArticleFooter"> <p> A paragraph containing author information </p> </div> </div>
This is actually all we need. If we examine the code, we'll see that we have given ourselves at least five"hooks", which is what we need to place customized graphics in each of the four corners (and left side) of our article.
• see Step 1 - primary markup
First let's decide on some basic layout parameters. Our graphic designer gave us this mockup for reference:
"I
want the borders and corners to look something like
this", he said. He also told us to beware of
the fact that all articles may have different width
and height, and that he still wasn't sure what kind
of background he wanted the articles to have. In
fact, he wasn't even sure those were the borders
he wanted. "Could
you leave that open, or make it so that it's easy to
change?",
he asked.
Ain't that always the case?
We set out to keep the number of "hooks" as
low as possible, so we'll have to pay extra attention
when we start to prepare the graphics for our solution,
and see if the graphics we need, are suitable to
be hooked up to elements we already have in our document.
We have a div containing the whole article.
That'll do for our top left corner, and top and left
sides. Header elements are by default
block level elements, and we'll take advantage of
their behaviour: they extend to
the full width of their parent element. So we'll use
the <h3> element
for our top right corner.
We'll
use our article-footer div for
the bottom left corner - and the contained paragraph
for our bottom right corner.
• step 1.1 – how we slice up the sketch
Obviously, you could use any element
to hook graphics up with. Maybe you are in a (very
likely) situation, where you do not have a document
structure like the one we're working with here.
Maybe you only have a single paragraph of text, you
want to apply customized graphics to. You could also
very easily do that. As stated above, all you need
is at least four structural elements (depending on
the height of your element you may need five), and
these elements could all very well be div's
each with their own class. Just remember
that for a div element to be rendered,
it needs to have content to manifest its presence.
However — the purpose of this article is to show that if you already have structural elements such as headers, paragraphs etc — you can and should use those.
We'll go on with that. First let's turn on borders
on our elements, and set a relative width for the
div that contains the whole article, to see
how things behave:
div.Article {
width:35%;
border: 1px solid red; }
div.Article h3 {
border: 1px solid blue; }
div.ArticleBody {
border: 1px solid black; }
div.ArticleFooter {
border: 1px solid blue; }
div.ArticleFooter p {
border: 1px solid magenta; }
• See step 2 – basic element behaviour
Nothing really surprising here. We do however
take notice of the gaps appearing before and after
our div class="ArticleBody".
Partly ignoring that for now, we'll go on and write
ourselves a stylesheet:
body {
background: #cbdea8;
font:
0.7em/1.5 Geneva, Arial, sans-serif;
}
div.Article {
background:
url(images/custom_corners_topleft.gif)
top left no-repeat;
width:35%;
}
div.Article h3 {
background:
url(images/custom_corners_topright.gif)
top right no-repeat;
}
div.ArticleBody {
background:
url(images/custom_corners_rightborder.gif)
top right repeat-y;
}
div.ArticleFooter {
background:
url(images/custom_corners_bottomleft.gif)
bottom left no-repeat;
}
div.ArticleFooter p {
background:
url(images/custom_corners_bottomright.gif)
bottom right no-repeat;
}
• See step 3 – first attempt
Not bad at all! Actually better than we expected. Obviously we need to add some padding to our respective elements to make it look better - and then there's the gaps. These are caused by the carriage returns inserted by our paragraph (block) elements. We could just avoid using paragraph elements all together, and thereby bypass this "problem", but we insist on keeping our markup nice and structurally clean and logic. It isn't our data's fault that we are lazy stylers.
We assume that a carriage return must
equal 1.5em,
since that is what we have specified for our line-height,
and therefore our first attempt was to add a margin-top:-1.5em
to our ArticleBody and ArticleFooter,
and that did the job in most standards-compatible
browsers
— except the ones used by the majority
of internet users on this planet. After testing,
trial, error, rinse and repeat we found that
we would have to use at least a margin-top:-2em
to be sure that the elements would "touch" and
the gap would close.
div.Article {
background:
url(images/custom_corners_topleft.gif)
top left no-repeat;
width:35%;
}
div.Article h3 {
background:
url(images/custom_corners_topright.gif)
top right no-repeat;
font-size:1.3em;
padding:15px;
margin:0;
}
div.ArticleBody {
background:
url(images/custom_corners_rightborder.gif)
top right repeat-y;
margin:0;
margin-top:-2em;
padding:15px;
}
div.ArticleFooter {
background:
url(images/custom_corners_bottomleft.gif)
bottom left no-repeat;
}
div.ArticleFooter p {
background:
url(images/custom_corners_bottomright.gif)
bottom right no-repeat;
display:block;
padding:15px;
margin:-2em 0 0 0;
}
• See step 4 - looks like we're finally there!
If you've been viewing this example in NS 4.x,
you've probably noticed that the page shows up
blank. We've found no way to get this technique to
work acceptably in NS 4.x, so instead we're going
to hide the styles that the browser in question cannot
render properly. NS 4.x does not understand style-tags
with media="all"
specified and we've taken advantage of that in the
example that follows. We've made two style-tags,
one with styles we want all browsers to render, and
another we want to hide from NS 4.x. Even though
it breaks our heart to do so, we've also changed
our font size specification from em's
to px's. You wanted backwards compatibility
- you got it.
• Step 5 - graceful degradation in NS 4.x
"Yeah - but we want to see real world applications
of this, mate", you say - and we anticipated
that, and provided an example of the technique
applied in a more advanced context. We borrowed an
already thoroughly
tested layout from Alex
Robinson, and applied
our styles to it — and we're glad we did!
Our first attempt opened a plethora of bugs and quirks
in IE6, triggering bugs affecting both z-index stacking
level of our elements, elements that disappeared
and margins acting like silly little children, but
then we learned that
a simple position:relative
and a well positioned <br /> fixed
it all. View the source in the example for further
investigation.
• Step 6 - our attempt at applying our technique to a full fledged layout with headers, columns and footers
If you have been paying attention, you probably already realized that this example only plays well with surrounding solid color backgrounds. With this method we need to cover the graphics from the top left corner with the graphics in the top right corner. If we made the top right corner graphic transparent, the top left graphic beneath it would show. Same goes for the bottom. And that is indeed a limitation, but what a great idea for a part deux of this article that would be, showing how working with ie. gradient backgrounds can be accomplished. This article did however demonstrate a generic method, with backwards-compatibilty and sound markup in mind, and it is our sincere hope that this will inspire alot of offsprings and ideas — perhaps even some that include working with not-solid background colors.
Brian Alvey for discussions, insisting on graceful degradation and real world examples, and David Schontzler for helping a danish guy write technical stuff in english.