Ran into an interesting problem recently.
My team created an HTML-based book preview application, called Slideshow, about two years ago. In one of its incantations, our app is embedded in a div on another page on our site. It looks like this:
This all worked well and good for many many months. About two weeks ago, however, a bug is assigned to us that says the navigation buttons are displaying as blank squares. Odd -- I jump onto our site to see if I can reproduce, and, sure enough, I see this:
The navigation buttons still behave properly, they just don't render on the page. I think maybe the assets are failing to load, but it appears that we're fetching, and successfully receiving, the proper graphic assets. So I inspect the elements, and there we find our problem:
The CSS for Slideshow's navigation buttons are being overridden by the host page's CSS, which has a global style giving all <a> tags white backgrounds and grey borders.
I check the revision history for the host page's CSS, thinking someone must've recently added this global anchor-tag style, but the css file hasn't been changed in months. What about Slideshow's CSS? Same story: it hasn't been changed in months. If none of the relevant CSS has changed, how could this have broken?
I search through some code, and I see that Slideshow's CSS is programmatically added to the end of the <head> element via JavaScript. Viewing the source of the host page, I see the offending CSS file is included within the <body> of the page. That sounds like it might be our problem: I'm betting that, even though Slideshow's CSS is added to the page last via a function call, it's being stomped on by the host page's CSS because it resides in the <body> of the page.
I investigate the host JSP: It includes a file called commonHeader.jspf, which basically looks like this:
<head>
<content tag="css">
<link rel="stylesheet" type="text/css" href="{our offending css}" >
<link rel="stylesheet" type="text/css" href="{some other css}" >
<link rel="stylesheet" type="text/css" href="{some other css}" >
</content>
<content tag="text/javascript">
{some javascript imports}
</content>
</head>
Strange -- it looks like the offending CSS *is* within the <head> element as defined by the JSP, but, when it is compiled into the served page, it ends up in the <body>. How does that happen? Well, it turns out we use sitemesh to decorate our page, and there is a totally separate header file that is automagically included in all of our site's rendered pages. That header file invokes a special tag to load content into itself (note the <content> tags in the above .jspf code), which means that the <head> and </head> tags in commonHeader.jspf are completely ignored by our site. Fun!
I investigate this newly found header file, and I see that someone made a change about a month ago that moved the tag that includes the "css" content from the <head> element to the <body> element. I swapped it back, and our Slideshow looked beautiful again. Hooray, our assumptions were correct! Loading the host page's CSS from within the <body> was causing it to overwrite Slideshow's CSS, even though Slideshow's CSS was loaded later.
So what did we learn from this adventure? First, we learned that our JSP rendering frameworks are not easy to trace, as it took an entire day's worth of searching -- and a little bit of luck -- to find the offending code. But, more importantly, we learned that it's a good idea to stick to the accepted standard of loading all external CSS files within the <head> of your page, even though most browsers, if not all browsers, don't strictly enforce it.
I did some Googling to see what other developers though about loading CSS in the <head> vs the <body> of a document, and most of the results spoke about best practices and page load-time (it turns out the browser is forced to re-render a page when it finds CSS in the middle of the document), which are great reasons in themselves. However, the issue we ran into shows that there can be actual render problems when CSS is included in the <body>, especially if other code is depending on that CSS to be located in the page's <head>, as Slideshow did when it added its own CSS to the dom.
What are your thoughts? Have you run into similar issues? Or, from the other side, have you ever found cause to include CSS, or JavaScript, within the <body> of your page? Tell me about it in a comment below!



No comments:
Post a Comment