ID Your Body Using PHP

By  on  

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?

Recent Features

  • By
    An Interview with Eric Meyer

    Your early CSS books were instrumental in pushing my love for front end technologies. What was it about CSS that you fell in love with and drove you to write about it? At first blush, it was the simplicity of it as compared to the table-and-spacer...

  • By
    Responsive and Infinitely Scalable JS Animations

    Back in late 2012 it was not easy to find open source projects using requestAnimationFrame() - this is the hook that allows Javascript code to synchronize with a web browser's native paint loop. Animations using this method can run at 60 fps and deliver fantastic...

Incredible Demos

Discussion

  1. Hmm.. my method with one regular expression:

    function generate_id($uri) {	  
        $url_id = preg_replace('/[^0-9a-z]{1,}/i', '-', $_SERVER['REQUEST_URI']);
        $url_id = trim($url_id, '-');
        return $url_id;
    }
  2. 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

  3. 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.

  4. 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

  5. @kilas: Nice!

    @Benjamin @ Virtuosi Media: Primary key would work too, although “page-1923” isn’t very descriptive when looking at your stylesheet. Comment well!

  6. ShawnD

    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="”>

  7. ShawnD

    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 %>”>

  8. Derrick Nelson

    @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.

  9. 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

  10. @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.

  11. @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

  12. 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.

  13. Nice post, great idea. Looks like your very last example is missing the generate_id() function call.

  14. 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.

  15. seelts
    function generate_id($uri)
    { 
    ...
    return preg_replace(
    array($regex1,$regex2,$regex3,$regex4),
    array('-','-','',''),
    $_SERVER['REQUEST_URI'] 
    );
    }
    

    It will be more logical to use $uri instead $_SERVER['REQUEST_URI'] in preg_replace() or remove it completely from the arguments list of a generate_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.

  16. 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.

  17. @Bam Roberts:
    oops, lost my body tag in the ctrl-c ctrl-v ing.

    I end up with

    <body id="shop-lenses-canon-50mm-f14-details" class="shop lenses canon 50mm-f14 details”>
  18. Jimmy B

    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

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!