Working in Content Management System (CMS) implementations has its challenges. While some of those challenges are in the application itself, many can be with the content authors. Content authors expect a certain amount of flexibility in how they can add or remove content on a page and we have to find a way to account for these variables. While not all CMS’ can, or are, built to be that flexible, SDL Tridion (which Tahzoo specializes in) certainly is, so we (at Tahzoo) often have to be creative with how we can solve the unknown variables that a content author can create.
Today I’m giving a real world example of how I met business requirements for a section on a page template that needed to adapt to the content author’s choices — using only CSS!
The Client
I’m not disclosing the name of the client because this is a current project; the HTML has been generalized for this reason. If you’re really curious to see this in action, let me know and I can send you a link when the implementation goes live.
The Use-Cases
We’re going to tackle three use-cases. All three use-cases will deal with exactly two pieces of content and their wrapper, which is #col-wide
. This one wrapper needs to be flexible to have 1, 2, or 0 content blocks. For those who know SDL Tridion, those content blocks are called components, and they’re wrapped in templates called Component Templates which is the content wrapped in HTML. I’m dealing with the “Article Small” template and the “Poll” template. So here are the business requirements that the client has given me:
- The content author can add a poll and a small article, and they both display
- If the content author adds only a small article, it takes up the full width
- If the content author does not add a poll or a small article, then the space is collapsed and everything below it will shift up
With that out of the way, now I’ll show you the markup:
Use-Case 3: Content Author Doesn’t Add Anything to the Container
You’d probably expect me to start by showing you how we write the CSS for both components, but we don’t. We’re creating a flexible layout, so we start with the smallest one first, and then build up to the highest.
Here’s the CSS that we’ll use when the container is empty:
#col-wide { width: 900px; margin: 0 auto; overflow: auto; border-top: 1px solid #d6d6d6; } #col-wide:empty{ display:none; } #col-wide > * { margin-top:25px; margin-bottom: 45px; }
We’ve given the container a set width, but not a height. We’ve also given it overflow:auto
. That’s so that it actually gets height, even when it has floated elements in it.
For the browsers that will allow it, I’ve used the CSS3 pseudo-class :empty
. You need to take special care in how you use it; it must not have anything in it at all. This means comments and even spaces! So :empty
is perfect for CMS’ that will generate purely blank elements, but unless you can guarantee an empty node, don’t rely on it.
Now, my wrapper originally had padding, but in order for me to deliver the new requirements, it needs to have a zero height when it’s empty — which won’t work if the wrapper has that padding. So I’ve used the direct descendant selector >
to apply margin to the two elements inside, instead. Disclaimer: I normally don’t recommend this. However, the figure
and article
are wrappers that live inside of the component templates, and the page template is developed to only allow these two component templates inside of this wrapper. I have a 100% guarantee that a wayward p
can never be put in here.
So at this point, I’ve got an element that either won’t display, or at least has zero height, when empty.
Use-Case 2: Content Author Adds the Article
We’ve gone from zero to exactly one component or content block in my wrapper. Now, in my two-component scenario, I’m going to need floats, but I haven’t gotten there yet with this use case.
#col-wide article{ float:none; width: auto; }
With just an article
, my rule is simple, it’s not floating, and the width is auto
so that it takes up as much space as it wants.
Use-Case 3: Content Author Adds both Article and Poll Component Templates
Now that I’ve built up to my two components, I need to deal with article
again. This time it needs to float, and it needs some width. That’s why I’ve made sure that in the HTML, figure
comes first. That’s because the sibling selectors only look for what’s after, not what’s before. For this to work, we always place the the last element first when writing our HTML. Doing so means it can act as the ‘hook’ for deciding whether we get a full-width or partial-width article. Because the figure
is that hook, we can use a sibling selector. We could have used the adjacent sibling selector ( +
), but IE7 has a lovely quirk where HTML comments will count as siblings, so ~
is my IE7 workaround.
#col-wide figure.poll ~ article{ float:right; width:605px; }
The sibling selector is perfect in this case because it allows us to almost create logic in our CSS. If we don’t have figure.poll
there, then this CSS doesn’t apply and we’ll just use article
‘s default properties, which are not floating and taking up full space.
With that out of the way, let’s add our figure
CSS:
#col-wide figure { width: 250px; float: left; margin-right: 45px; }
Now we’re finished! We’ve accounted for three different choices that our content author can make, and we did it without re-writing the page template, forcing the content author to pick a new template, or forcing the content author to change the component template that the content gets wrapped in. Even better, it works in all the major browsers and it doesn’t require JavaScript.
The Big Idea
The sibling selectors can serve as a sort of ‘DOM detector’ or logic control. Using the +
and ~
should be part of your daily vocabulary when you’re writing CSS that goes into a CMS. And if you want a general outline of the CSS Selectors, I wrote a blog post on that, too.