By default, only the html and the body element (plus its children) of a web page are actually rendered. All information within the head element might be parsed and used by the browser, but most of the time it doesn’t get displayed. If you want to, you can use CSS to display these ‘hidden’ elements.
I used to do this on my old site, but then I renewed it, so I just thought I’d document this little ‘trick’.
Wait, what?
It’s pretty simple actually — just look at it this way… Browsers apply the following CSS rule to every document:
head, title, link, meta, style, script {
display: none;
}
As with all browser-default CSS, this can be overridden by declaring the following style rules:
head, title, link[href][rel], meta, style, script {
display: block;
}
This one CSS rule is all it takes to force the browser to display the elements.
Of course, there are a few other things you might want to do — adding inner content to the link and meta elements, for example.
Use generated content for added coolness
link[href][rel]::after {
content: attr(rel);
text-transform: capitalize;
}
meta[charset]::after {
content: 'Charset: ' attr(charset);
}
meta[name][content]::after {
content: attr(name) ': ' attr(content);
text-transform: capitalize;
}
Similarly, we can style script elements with a src attribute specified:
script[src]::after {
content: 'External file: ' attr(src);
}
To target only inline script blocks, we could use the CSS3 negation pseudo-class:
script:not([src]) {
background: lime;
}
Use JavaScript for even more cross-browser coolness
Firefox is the only browser that seems to automatically create clickable links out of visible link elements with a href attribute. This is pretty useful — the link element sort of becomes a hyperlink pointing to the resource it was referring to. To clone this behavior in other browsers as well, we can use JavaScript:
<script>
function() {
var head = document.head || document.getElementsByTagName('head')[0];
var links = head.getElementsByTagName('link');
var length = links.length;
while (length--) {
links[length].onclick = function() {
location.href = this.href;
};
};
}());
</script>
This script simply loops through all link elements inside <head> and adds onclick handlers to them, causing the referenced document to be opened upon clicking.
Demo
You can see this technique in action on the demo page. Believe it or not, this is a document with an empty <body>!
Sadly, this fails in Internet Explorer (I’ve tested versions 6, 7, 8, 9 and 10). Nonetheless, I think this is a pretty interesting trick.
Comments
riddle wrote on :
Try
script:not([src])–:not()works when it gets a simple selector.Mathias wrote on :
riddle: Thanks for the tip! So, according to the spec, is
script:not(script[src])supposed to work or not? It seems to work in nightly WebKit builds.riddle wrote on :
Yes, that’s right. See,
script[src]isn’t simple – it’s like.class1.class2(note the lack of space), one’s refinement by the other.And when you really think about it, you basically say: take all
scriptelements and dismiss allscriptelements that have asrcattribute. It’s clearly redundant – we only have a bunch ofscriptelements anyway. Using an attribute just makes sense. :)But yeah. Just simple. Meaning
.class,[type="text"],#idordiv. :)Diego Perini wrote on :
The
htmlelement is also rendered and you can change it by means of CSS rules like any other element (and this is somewhat useful).I still don’t get how changing the
displayproperty ofmeta,scriptandstyleelements could be thought as useful for the WEB :) There are a lot of things that can be done in an HTML document, the question is: are these things useful?And about
script:not(script[src]), it is incorrect by specs and doesn’t work in my Safari 5. Further on, even if that was working, you are slowing down the browser selector engine by repeating twice thescripttag when only one is enough if written as the specs recommend. Frameworks like jQuery will accept the wrong syntax you are suggesting but that’s an error as far as specifications are considered.In this case jQuery will return inconsistent results between browsers having
querySelectorAll()and those not having it (IE, Firefox < 3.1, Opera < 10 etc.).I prefer cross-browser consistency over crippled extensions to the specs.
That said, specifications change frequently and I could have to retract some of those assertions one day, though I believe this to be highly improbable.
Mathias wrote on :
Diego: You’re right about the
htmlelement being rendered as well. I should have worded that more carefully. This is indeed very useful, because thehtmlelement can be used as abodywrapper in CSS. I’m actually doing that on this site (and every other site I develop).I never said making hidden elements visible through CSS is a ‘useful’ technique, nor that people should actively start using it in production; I just found it to be interesting and good to know.
Johan Sundström wrote on :
It would be neat with a little bookmarklet that crafts a stylesheet for the current page which simply adds a
<style>element (or, if present already with the exact CSS added, toggles its boolean.disabledproperty) that adds the appropriate "display: block":s, the "*:before":s and "*:after":s matching all the exact html tags and attributes used in the page (makinghtml,head,body,meta:s,script:s,link:s,style:s, and all the other non-rendered tags show, with their values, as they would look in the page source (probablywhitespace: pre-wrapped), greatly reducing the need for “view source” for mere inspection (or even some copy-and-paste type operations). Example:I guess the js part has to permute all the {has-/lacks-}attribute combinations for the
:before:s itself, which might get hairy for multi-attribute elements found, but it would be a rather useful (and cool :-) tool.Neat feature with the
contenteditableattribute addition forscriptandstyletags, by the way!Mathias wrote on :
As a follow-up to riddle’s remarks,
:not()and:matches()will accept any selector (not just simple ones) in CSS Selectors Level 4. Good to know :)Nikita Vasilyev wrote on :
I went one step further by making JS editable, too. Here is the demo: http://elv1s.ru/files/dom/quine.html
Burak Yiğit Kaya wrote on :
Great trick! I tried it on IE9 and IE10 though and it does not work.
bga_ wrote on :
Opera 12- has several built-in user-stylesheets that use this technique to display HTML structure, class names, attributes etc. See http://www.opera.com/docs/usercss/#user-mode. The source can be found in
%OperaInstallPath%\Styles\user.