By default, only the html
and the body
element (plus its descendants) 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?
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
script
elements and dismiss allscript
elements that have asrc
attribute. It’s clearly redundant – we only have a bunch ofscript
elements anyway. Using an attribute just makes sense. :)But yeah. Just simple. Meaning
.class
,[type="text"]
,#id
ordiv
. :)Diego Perini wrote on :
The
html
element 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
display
property ofmeta
,script
andstyle
elements 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 thescript
tag 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
html
element being rendered as well. I should have worded that more carefully. This is indeed very useful, because thehtml
element can be used as abody
wrapper 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.disabled
property) 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-wrap
ped), 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
contenteditable
attribute addition forscript
andstyle
tags, 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
.