ID Your Body Using PHP
It seems like every part of a website needs to be dynamic. Dynamic, database-driven pages, dynamic JavaScript, dynamic CSS, etc. All this dynamism can make it difficult to style or script a page easily. One way I've learned to combat the rigidness of using CMS' is to give the BODY element a unique ID based on the URL. Doing so allows me to add special styling to any page.
The PHP
function generate_id($uri) { /* regular expressions */ $regex1 = '/[^a-zA-Z0-9]/'; //remove anything but letters and numbers $regex2 = '/[\-]+/'; //remove multiple "-"'s in a row $regex3 = '/^[-]+/'; //remove starting "-" $regex4 = '/[-]+$/'; //remove ending "-" /* return... */ return preg_replace( array($regex1,$regex2,$regex3,$regex4), array('-','-','',''), $_SERVER['REQUEST_URI'] ); } /* do it! */ $body_id = generate_id($_SERVER['REQUEST_URI']);
The above code uses preg_replace to find "bad" or repeated characters and replace them with dashes or nothing. I don't claim to be a regular expression genius so there may be a better way to construct the preg_replace regex parameters. Let's take a look at some example usages:
//assuming the page URI is: /some-directory/deeper/my-page $body_id = generate_id($_SERVER['REQUEST_URI']); //returns: some-directory-deeper-my-page echo '<body id="',$body_id,'">';
The above uses the page URI to build out the body ID, joining the "page name" with its directory.
//assuming the page URI is: /some-directory/deeper/my-page?category=mootools $body_id = generate_id($_SERVER['REQUEST_URI']); //returns: some-directory-deeper-my-page-category-mootools echo '<body id="',$body_id,'">';
The above uses the page URI, including the GET parameters.
//assuming the page URI is: /some-directory/deeper/my-page.php?category=mootools $body_id = generate_id($_SERVER['REQUEST_URI']); //returns: some-directory-deeper-my-page-php-category-mootools echo '<body id="',$body_id,'">';
The above shows how a non-search-engine-friendly URL being parsed. If you'd like, you can remove the ".php" file extension from the URI.
Using CSS
body#my-dir-my-page { /* custom formatting for this page */ }
The above shows you how you can leverage the new ID to your advantage when it comes to specialty CSS for the given page.
A Few Thoughts
- I've chose to use the ID attribute -- you could easily make it a CSS class instead. Since this generated string should be unique (at least theoretically), I prefer the ID.
- If you aren't using SEF links, I recommend removing the file extension -- if not just for cleanliness.
- Keep the query string parameters if they're relevant/unique per that page. You may want to make the page the ID and add a class of the querystring parameters:
//assuming the page URI is: /some-directory/deeper/my-page?category=mootools list($id,$class) = explode('?',$_SERVER['REQUEST_URI']); echo '<body id="',$id,'" class="',$class,'">'; //returns: <body id="some-directory-deeper-my-page" class="category-mootools">
What are your thoughts? Do you do anything like this?
Hmm.. my method with one regular expression:
Since the friendly URL is usually based on the page title, once you change the page title you need to change the CSS. So in my opinion this solution works only for personal website not for a let’s say corporate website.
If you use this solution for well establish sections of your website Eg: blog, contact then this solution works
I like the idea. If you were doing it within the context of a CMS, you could just use the primary key for the page id which should always be unique and it would be shorter to type than the URL slug.
Only useful and reliable if you can make sure that there’s only one way to access a certain page. Example: /folder/index.php?myquery=test vs. /folder/?myquery=test&uselessParameterAddedByUser=1337
@kilas: Nice!
@Benjamin @ Virtuosi Media: Primary key would work too, although “page-1923” isn’t very descriptive when looking at your stylesheet. Comment well!
I do something less sophisticated but still effective for our sites.
We are exclusively and ASP and ASP.Net shop so this one is classic ASP:
<body class="”>
hmm lets try that again. Sry, i assumed the tags would get converted automatically.
Code —
<%
‘lets get the page name and use that as a class for the body.
‘this allows us to target CSS on a per page basis
dim svScriptName : svScriptName = Request.ServerVariables(“script_NAME”)
‘remove / and file extension of .asp
svScriptName = replace(svScriptName, “/”, “”)
svScriptName = replace(lcase(svScriptName), “.asp”, “”)
%>
<body class=”<%=svScriptName %>”>
@kilas: Your function doesn’t accomplish what his does, although it’s similar. If you look closely, you’ll notice that he’s reducing -‘s in order to prevent IDs like some-dir-some——-page-php. I’m not sure if repeated -‘s are valid CSS, but if they are, your function is probably more reliable than his, due to less likelihood of producing ID collisions.
I had to do something like this on a recent project. Only thing is I needed a more versatile solution. For example, what if you want your CSS from one page to inherit from another page. You can do that with ID’s if you have one ID nested inside another. But you can’t have one BODY tag nested inside another, so I went with DIVs. This also let’s me load one page within another (for example, loading into a modal window) and preserve all the styles of the original page – so long as all relevant styles target the ID’s. If you also use the ID’s to target Javascript behavior same thing – load a page into another page and preserve all original behavior. Anyway, result is here – worked well so far: http://www.cafebritt.com
@Derrick Nelson: Hmm.. I dont understand. Check this:
My method:
Filename: —-1_d——-rzewo’—–.php
Result: mashup-1-d-rzewo-php
by David:
Filename: —-1_d——-rzewo’—–.php
Result: mashup-1-d-rzewo-php
Give some examples.
@Derrick
Check the kilas’s regexp: /[^0-9a-z]{1,}/ – could also be written as /[^0-9a-z]+/ – which means “one or more” instances of a match are written as a single dash. So… same thing…
If we’re comparing functions to generate slugs… I like the one from Cake – which also handles special characters gracefully:
http://api.cakephp.org/view_source/inflector/#line-493
I’ve re-written it for Javascript (had to encode the special characters to avoid problems with YUI compressor):
http://pastebin.com/f4cd741a0
And even Coldfusion (if you like pain):
http://pastebin.com/f597de5ad
WordPress does that thing with post-ID but I almost never used it in CSS, becuase I want to write the page/post without changing the CSS every time.
But I guess it would come in use on the body of a page. Hm, I would use the pagename probably, to make it shorter without dirs.
Nice post, great idea. Looks like your very last example is missing the generate_id() function call.
Interesting. Think I might adopt a method out of this, utilizing either the name of the page’s Class name if it’s PHP or Package name if it’s Perl. Could also look at using it via Namespace::Class (namespace_class).
Very intriguing. You site motivates me to continue developing a programming help blog.
It will be more logical to use
$uri
instead$_SERVER['REQUEST_URI']
inpreg_replace()
or remove it completely from the arguments list of agenerate_id
function to be able to write$body_id = generate_id();
but it was an offtopic… now question!
as i’ve understood, you use it to be able to apply different styles, depending of what page is loaded. does it mean that you give to user a css that has all styles for all possible body ids?
doesn’t it perversion? it seems to be easier (and “natural” may be) to generate necessary style sheet or to choose what css will be included before giving it to user.
Hi David,
Good post, I been using something similar to this in my frame work, but i split the sections into an array and then pop them one at a time into the class name.
If I have the url http://www.mysite.com/shop/lenses/canon/50mm-f1.4/details/ i end up with this lets me style by all sorts of extra variables, like having canon specific branding, department background images and differing icons.
With CSS3 you can also write body.lenses.details{…} for even more granular control.
@Bam Roberts:
oops, lost my body tag in the ctrl-c ctrl-v ing.
I end up with
My shop is mostly Modx CMS based. Luckily Modx makes it really easy to get page specific CSS onto a specific page (or onto a page and all it’s children). It’s very nearly automagic.
Here’s how we do it:
http://wiki.modxcms.com/index.php/Dynamic_CSS_with_TVs