It all started with a photo that I made in a bathroom at the Royal Academy of Arts. The picture shows me, taking a picture of myself via a mirror, using a lot of flash. On the mirror, the word heaven
is pasted (probably by another student for some sort of project). The photo has been the inspiration for various personal site designs.
It started out with a simple page that was build up with table
hacks and an iframe
, at a subdomain of fragile minds dot com. The design you're currently looking at (assuming you use a graphic browser, did not apply a nalternate or cutom style sheet, and it's still April 2004) is called Mirror to Heaven 5
, but a name like Mirror to Heaven 24.6 revision 85
would probably be more accurate. Blah.
Something I've been meaning to do since the first implimentation of a Mirror to Heaven theme on my previous home page is to break down the code and explain its features and the the choices I made. It's one of the most flexible/elastic style sheets I've created (or seen, for that matter).
The flexibility/elasticity comes from the fact that everything but pixel based images is linked to initial the font size, and even that initial font size is relative to the the setting of the user agent (x-small). Not only the paragraphs and headers are directly linked to the font-size, but also the dimensions of containers and even the thickness of borders. The only thing that is not relative are the dimensions of pixel based images (img
); simply because the results would be ugly (vector based images like SVG are relative also).
Another nice thing about this theme is that every browser can handle it. Sure, you need to run the latest Mozilla + SVG build to see all the fancy CSS trickery, but it will also display perfectly well if you do not. I've tested the site in Internet Explorer on Windows, Opera, Netscape 2 to 7 (yes, that includes Netscape 4.7x!), and many others, at various screen resolutions and various font size settings. Here are some screenshots:
Ok, now that you've seen what I'm talking about, let's break down the code.
* { background: transparent; color: inherit; font: normal 1em inherit; margin: 0; padding: 0 }
This rule resets the background, color, margin and padding values of all XML elements, and should reset the .font-family
, font-size
, and font-weight
values
abbr, acronym { border: none; font-style: inherit /* Silly Safari */ }
Safari renders abbr
and acronyms
italic by default. An odd choice if you ask me, but it wouldn't be as much of a problem if it wasn't for the fact that abbreviations and acronyms often consist of capitals. I love italics, and I love capitals, but I have problems with italic capitals — especially when they are rendered by small pixel fonts.
input, table, textarea { font: normal 1em Verdana, Helvetica, sans-serif } /* Sigh */
This rule is even more redundant than that it's silly. This should have been taken care off by the first rule, but I haven't come across one browser that interpreted * { font: normal 1em inherit }
correctly (No, not even Mozilla.)
a img { background: #eee; border: .1em solid #ccc; margin: .2em; padding: .3em }
This rule applies to all images (img
) that reside inside a anchor (a
), which — when I use them — are always image links. The rule adds a border, and a padding value that (working with the background values that are defined elsewhere) works as another border.
becomes
address, cite, dfn, em, i, var { font-style: italic }
b, button, h4, optgroup, strong, th { font-weight: bold }
These rules specifies which elements should be rendered bold or italic. The values are default for most — if not all — visual browsers, but they're reset by the first rule of the style sheet. These rules put them back.
blockquote { border: .1em dotted #ccc; margin: 1em; padding: 0 1em }
This rules adds a dotted border to blockquote
s. Internet Explorer renders a dashed border instead of a dotted one, but I can live with that.
body { font: normal x-small Verdana, Helvetica, sans-serif; padding: 2em }
This rule sets the font-weight
value to normal, the font-family
to Verdana (and if Verdana is not installed; Geneva, and if Geneva isn't installed either; the user agent's default sans-serif font) to the body
element. The font-size
is set to x-small (extra small) � the exact size of the font on screen is dependant on the user agent's setting. All other dimensional values of the style sheet are directly connected to this generated value.
code, kbd, samp { font: normal 1em Lucida Console, Verdana, sans-serif }
The default font-family
value of most user agents is monospace. This rule forces user agents to use Lucida Console, when available. If Lucida Console is not available, the user agent is forced to use Verdana, which is the default font of this style sheet.
del { text-decoration: line-through }
This rule puts a line through all del
elements. This value is default for most visual browsers.
dl, ol, p, ul { padding: 1em 0 }
Adds padding values to lists and paragraphs. I prefer this over the default margin values that most user agents use (which are undone by the first rule of this style sheet).
form { text-align: right /* I like clicking stuff on the right side */}
Aligns all text and objects that reside inside a form to the right (default is left).
h1 { font: normal 4em Georgia, Times, 'Times New Roman', serif }
h2 { font: normal 2em Georgia, Times, 'Times New Roman', serif }
h3 { font: bold 1.111em Georgia, Times, 'Times New Roman', serif; letter-spacing: .2em }
Typographic rules for headers. I particulary like Georgia for its numbers. If Georgia is not available, Times is used instead. If Times is also unailable, these rules make sure another serif font is applied.
h5, small, sub, sup { font-size: smaller }
This rule applies to elements that should be rendered smaller than its parent. How much smaller exactly, is up to the user agent, really.
html { background: #999 url(html.gif) repeat-x bottom fixed; color: #666 }
These rules set the background color, and default text color of the root element (html
). It also specifies the gradient that should appear at the bottom of the background.
input, textarea { border-color: #999 #ccc #fff #ccc; border-style: solid; border-width: .1em }
This sets the appearance of borders of user input elements (input fields and textareas). Internet Explorer also applies these rules to radio buttons (input type="radio"
), I don't think this is wrong behavior, but I don't like the look of it, and unfortunately cannot be undone with input[type=radio] { border: none }
(maybe it can with the use of some JScript, I'll look into that later).
ins, u { text-decoration: underline }
Underlines all ins
and u
elements.
li { margin-left: 2em }
Adds a margin of 2em to the left side of all list items.
ol { list-style: decimal outside }
Makes sure that list items that reside inside a ordered list are tagged with decimal numbers (starting with 1).
pre, table, textarea { overflow: auto; width: 100% }
These rules make sure that the width of predefined text, tables, and textareas are equal to that of their parent. If the content forces the elements to be wider than its parent, scrolling is applied.
td, th { border: .1em solid #eee; padding: .2em }
This rule sets border and padding vallues for table cells and table header cells. The borders are not visible since they have the same color as the background (that is defined at a later point) � they are initiated for visual effects that are defined by dynamic pseudo classes.
ul { list-style: square outside }
ul li ul { list-style: disk outside }
First level list items that reside inside a unordered list are labeled with squares. Second level list items are labeled with disks.
html { border-top: .1em solid #000 }
body { border-top: .1em solid #666 }
These rules style the little gradient at the top of each page (). The gradient is build up from two borders — a dark grey one on the body
element, and a black on on the html
element. The reason that the black border is thicker than the dark grey one is that the font size is set to x-small on the body
... On the html
element, the font size value is still default (small).
blink, center, embed, font, marquee { background: red; text-decoration: none }
If either one of these particular elements were to appear on my site, the background color would be red so I would notice. I've currently scripts set up that filter these elements from user comments, and I don't use them myself, so you won't see them on this site.
q:after { content: close-quote }
q:before { content: open-quote }
The reason these rules are here is that this is how it's supposed to be done. I don't think they serve any real life purpose since every browser that supports these pseudo-elements render quotes on q
elements by default anyway.
input:focus, textarea:focus { background: #fff }
These rules are responsible for some special effects. If there is focussed upon a input field or textarea, the background color is set to white (which is transparent by default).
:link { color: #009; text-decoration: underline }
:visited { color: #900; text-decoration: underline }
:link:hover, :visited:hover { background: transparent; !important; color: #090 !important }
These rules take care of the colors of hyper links. New links are a dark blue and visited links are a dark red. Hovering over a link (whether its new or visited) causes the text to turn a dark green. The background color of hyper links is always set to transparent.
a:hover img { background: #fff; border-color: #999 }
This rule causes the default background color of images that reside inside anchors (a img
) to go from transparent to #fff (white) when hovered.
becomes
*:lang(la) { font-variant: small-caps }
Text that is written in Latin is rendered in small capitals (real capitals are maintained).
ol:lang(la) { list-style: upper-roman inside }
List items that reside inside a ordered list are labeled with roman capitals instead of the decimal numbers, when the text is in Latin.
q:lang(en) { quotes: '\201c' '\201d' "\2018" "\2019" }
q:lang(fr) { quotes: '\0ab' '\0bb' "\2018" "\2019" }
q:lang(nl) { quotes: '\201c' '\201e' "\2018" "\2019" }
These rules take care of the type of quotes that is used for all q
elements (quotes) for specific languages.
:link[rel~=muse]:hover img { background-color: #dcc !important }
:link[rel~=crush]:hover img { background-color: #ecc !important }
:link[rel~=date]:hover img { background-color: #fcc !important }
:link[rel~=sweetheart]:hover img { background-color: pink !important }
Some additional styling for images that reside inside links (a img
), that are XFN friendly. It changes the background color on hovering from white to a shade of pink. The stronger the romantic relation is, the more intense the shade of pink is.
@media all {
Things get complicated from this point. Netscape 4.7x doesn't like complicated. This rule hides the following rules from Netscape 4.7x.
Now comes the most important part. This section takes care of the positioning of elements and general layout. This is less about details, and more about the actual presentation.
#root { background: #eee url(pin_ccc.gif) repeat; border: .1em solid #000;
margin: auto; max-width: 100%; width: 65em }
#root
is the general container. All content on every page resides inside a div
element with and root ID. As you can see, the container's width is 65em, this means it's directly linked to the default font size (which is x-small, and then dependant on the user agent's settings). This means that when a user agents changes the font size value, the width of the container changes too, and so the number of letters/words per line remains the same. However, when 65 times the font size is more than the width of the view port, the containers' width is brought back to the width of the view port (minus the padding values of the body
element) — this prevents the need for horizontal scrolling.
It also specifies the pinstripe background (), and margin: auto
centers the container (if the user agent supports it).
#root > * > * > * :link, #root > * > * > * :visited { color: #999; text-decoration: none }
#root > * > * > *:hover :link { color: #009; text-decoration: underline }
#root > * > * > *:hover :visited { color: #900; text-decoration: underline }
This is some bleeding edge CSS magic
. What it does, basically, is hide the text decoration (underline) of all hyper links, and bring it back for a section when the user hovers over that particular section. For browsers that support this feature, it also overwrites the hyper link rules, and sets all the link colors to grey, only to bring them back in the same way as the text decoration.
I'd say it's easier to see what it does by hovering over the various elements on this page, but since most visitors are not using a browser that supports it properly (and this article will eventually be outdated), I'll provide some screenshots.
The first screen shows a menu from one of the pages on this site. The second screen shows the same menu, but when I was hovering my cursor over a particular section of the menu. Note that all the links in the section I was hovering over have colors (blue for new links and red for visited links) and are underlined. You might notice a difference in intesity of the regular text and border colors, but I'll get to that later. Users of Internet Explorer always see the colors and underlines.
#root > * > * > *:hover a[type='application/rss+xml'] { background: red;
color: #fff !important; font-weight: bold; text-decoration: none }
This rule makes all links that are of type application/rss+xml (for site syndication) bold, white on red, and without underline, but only when the user hovers over the parent section (there's currently few browsers that will display it correctly).
#header { background: #eee; border-bottom: .1em solid #999; border-top: .1em solid #fff;
padding: .5em 1em }
Set the background color for the header, and adds borders for the 3d effect (and some padding to make its children align properly).
#header #logo { display: inline; font-size: 2em; font-weight: bold }
#header #logo a { color: #999 !important; text-decoration: none }
#header #logo a:hover { color: #000 !important }
Rules for styling the logo (), which is in fact a anchor (a
) inside a h1
. Default h1
and :link
rules are overruled.
#header ul { display: inline; list-style: none }
#header ul li { display: inline }
It might not appear that way, but the chapter links in the header are actually list items in a regular unordered list. These rules make them appear like inline elements. Most browsers set the list-style
to none when the display
value is set to inline (which makes sense), but since some browsers do not (Safari comes in mind), I forced it with the rule list-style: none
.
#description { background: #eee; border: .1em solid #ccc; margin: 1em 1em 0 1em; padding: 0 1em }
#description:hover { background: #ffc; border-color: #999; color: #000 }
The first rule is some generic styling to make page descriptions (which consist of div
elements with an ID od description) blend in nicely with the rest of the design. The second causes the background to turn a soft yellow when a user hovers over the div
(only supported by few browsers).
becomes
#body .header { background: #333; border-bottom: .1em solid #fff;
color: #fff; height: 8em; padding: 1em; text-align: right }
Below the header with the logo and chapter links, on each page there's a banner that carries the title of that particular page (and sometimes some additional text or a specific background image). These rules set the default background color of these banners to a very dark grey, a height is specified (which, again, is linked to the font size), and a border is added for the sake of the 3d look.
#body .menu { float: right; max-width: 100%; width: 16.25em }
This rule forces the menus (div
elements with a class of menu) to float left, and sets the width to a fraction of the width of the general container (#root
). The width of the menus is forced to 16.25em by default.
#body .menu dl { background: #eee; border: .1em solid #ccc;
margin: 1em 1em 1em 0; padding: .5em }
#body .menu dl:hover { border-color: #999; color: #000 }
The first rule sets the border, margin and padding values of description lists that reside inside menus (and are treated as menu items) to fit the general design of the site. The second rule set the text and border colors to a darker grey when the user hover over the item.
#body .section { background: #eee; border: .3em double #ccc; clear: both;
margin: 1em; padding: 1em }
#body .section:hover { border-color: #999; color: #000 }
These rules work the same as they do for menus, but apply to sections... content sections, to be specific. The difference is that sections don't get a single border, but a double one (border: .3em double #ccc
)... and yes, even the width of the double borders of section is linked to the font size.
#body .section h2:before { color: #ccc; content: '\0a7\0a0' }
#body .section:hover h2:before { color: #999; content: '\0a7\0a0' }
The first rule places a section sign () in front of every instance of a h2
that resides inside a section (div class="section"
). There are currently few browsers that support it. The second rule changes the color of this sign into a darker grey, when the user hovers over the section. Needless to say, very few browsers get this one right — even Opera fails this one.
#body .section:hover tr td, #body .section:hover .subsection { border-color: #ccc }
These rules change the predefined border colors of table cells (td
) to a slightly darker gray when the user hovers over its parent section. This also goes for subsections (div class="subsection"
).
#body .section tr:hover td { border-color: #999 }
For the sake of readability of tables, I added this rule that makes the borders of table cells an even darker grey when a user hovers over its parent table row (tr
).
I wanted to add a similar rule for table columns (col
), but not one single browser appeared to support it. Mozilla does support some styling of columns (like the background color), but it will not play nice in combination with dynamic pseudo-classes (:hover
).
#body .subsection { border: .1em solid #eee; clear: both; margin: 1em 0; padding: .4em }
#body .subsection:hover { border-color: #999 !important }
Some additional styling for subsection (div class="subsection"
).
#content { float: left; max-width: 100%; padding-bottom: .5em; width: 48.5em }
Styling of the actual content. #content
is a div
elements with an ID of content, and contains all sections and subsections. The content container is forced to float to the opposite side of menus, being left. The width initially is set to 48.5em. When the viewport is too small to fit the content and the menus next to eachother, the floats are broken, and the menus and content appear on top of eachother instead of next to eachother. The content container has a maximum width of 100% to prevent the need of horizontal scrolling, even when the viewport is too small to host the width of the content container alone (48.5em).
#footer { background: #eee; border-bottom: .1em solid #999; border-top: .1em solid #999;
clear: both; text-align: center }
Does the same thing for the footer as the rules for the header do, but also centers the text (copyright).
#footer p { border-top: .1em solid #fff }
Again, some border for the sake of a 3d look.
} /* /media all */
Tell Netscape 4.7x it can open its eyes again — the horror is done.
.censored { background: #000; color: #000 }
.date { font-variant: small-caps }
.description {}
.gallery { text-align: center }
Styling of some generic class names I use throughout the site. Elements with a class censored are blacked out, elements with a class of date are rendered in small capitals, and text and elements that reside inside an element that carries a class of gallery are centered.
body.people [href='/people/'] { color: #ccc !important }
body.photos [href='/photos/'] { color: #ccc !important }
body.portfolio [href='/portfolio/'] { color: #ccc !important }
body.projects [href='/projects/'] { color: #ccc !important }
body.weblog [href='/weblog/'] { color: #ccc !important }
These rules overrule the color values of hyper links when they are linking to a page from the same chapter (which means it carries the same class in the body
element).
These are a lot of fun to do. I had a lot more, but removed most of them. I will implement more later.
body.freecell #body .header { background: #007f00 url(freecell.gif) no-repeat center }
body.freecell #body .header:hover { background-image: url(freecell-hover.gif) }
These rules apply to all pages that carry a class of freecell on the body
element (this is only the FreeCell page). The first rule sets the background color of the banner to the same green that is seen in the Windows FreeCell game (#007f00) and places the face of the king from the game in the middle. The second rule makes the face of the king flip horizontally when the user hovers over the banner (very much like it does in the game). Only few browsers support this feature.
becomes
body.music #body .header h1:before { content: '\266b' } /* Force music symbol */
This rule generates a Beamed Eight Notes sign in front of the title in the banner of the page that carries the class music on the body
element (which is the music page). Since the generated sign is made of text, it respects the font size setting. The following example show the title from the banner when the font size is set to 50%, 100% and 200% in my copy of Mozilla:
body.painting #body .header { background: #333 url(painting.jpg) no-repeat center }
body.people #body .header { background: #333 url(people.jpg) no-repeat center }
body.portfolio #body .header { background: #333 url(portfolio.jpg) no-repeat top right }
body.projects #body .header { background: #333 url(projects.jpg) no-repeat top left }
These rules set specific background images for various pages. The images are a lot bigger than the size of the banners they apply to when using common default user agent setting. This way, changing the font size value does not cause ugly margins between the the borders of the images and the borders of the banners, but merely shows more of the images.
body.projectsmirror #body .header { background: #999; color: #666 }
body.projectsorkut #body .header { background: #D4DDED; color: #AC0481 }
The first rule sets the background and text colors of the banner of my Mirror Project page to match the style of The Mirror Project. The second rule sets the background and text colors of my orkut page to match the style of orkut.
body.weblog #body .header { background: #333 url(weblog.jpg) no-repeat top left }
Last, but not least, this rule sets the background image for the banner of this very weblog.
ACJ2 comments so far.
Hi Acj, what's up? I love the new site design, once again I envy your coding and designs skills and can only dream of being at that level one day. Congrats on the XHTML 1.1 by the way, very impressive. Well, better get back to work. Talk to you later.
-NS aka Tanisha
Posted by: NovaStarr on May 5, 2004, at 19:52
Hey hey, I'm not doing too bad, how about yourself? Thanks for the compliments. :)
Posted by: ACJ on May 6, 2004, at 04:15