Truly Terrible Tabs for the Broken-Hearted
Tab Controls Using Only CSS
It is possible to create a tab control using only BBCode and appropriate CSS styling. This technique relies on the anchor tag, which is a link that reloads the page scrolled down to a specified location. It is most typically used for in-article tables of content. The original technique was described in an article way back in 2003 by Bert Bos, inspired by a blog post by Daniel Glazman in that same year. This is just a translation of that technique to WA BBCode. Nota Bene: This feature requires the ability to set containers with custom CSS classes, which limits its utility to Grandmaster and above. Here are the tabs in action:Tab 1Hi, I'm some tab dope
Tab 2More tab-dope insanity, with more content.
For example, here is some additional text.
Happy families are all alike; every unhappy family is unhappy in its own way.
Everything was in confusion in the Oblonskys’ house. The wife had discovered that the husband was carrying on an intrigue with a French girl, who had been a governess in their family, and she had announced to her husband that she could not go on living in the same house with him. This position of affairs had now lasted three days, and not only the husband and wife themselves, but all the members of their family and household, were painfully conscious of it. Every person in the house felt that there was no sense in their living together, and that the stray people brought together by chance in any inn had more in common with one another than they, the members of the family and household of the Oblonskys. The wife did not leave her own room, the husband had not been at home for three days. The children ran wild all over the house; the English governess quarreled with the housekeeper, and wrote to a friend asking her to look out for a new situation for her; the man-cook had walked off the day before just at dinner time; the kitchen-maid, and the coachman had given warning.
More tab-dope insanity, with more content.
For example, here is some additional text.Happy families are all alike; every unhappy family is unhappy in its own way. Everything was in confusion in the Oblonskys’ house. The wife had discovered that the husband was carrying on an intrigue with a French girl, who had been a governess in their family, and she had announced to her husband that she could not go on living in the same house with him. This position of affairs had now lasted three days, and not only the husband and wife themselves, but all the members of their family and household, were painfully conscious of it. Every person in the house felt that there was no sense in their living together, and that the stray people brought together by chance in any inn had more in common with one another than they, the members of the family and household of the Oblonskys. The wife did not leave her own room, the husband had not been at home for three days. The children ran wild all over the house; the English governess quarreled with the housekeeper, and wrote to a friend asking her to look out for a new situation for her; the man-cook had walked off the day before just at dinner time; the kitchen-maid, and the coachman had given warning.
Some Comments
- You will note that clicking the tabs reloads the page with the tabs "near the top." The actual position of the tabs is dependent on a couple things:
- How much text is below the tabs. If the tab control appears near the bottom of your page, the browser will reload the page as far down as possible, but it won't necessarily be right near the top.
- How much padding and margin you put above the tabs. The browser wants to reload the page with the tabs against the top of the viewport, which may be hidden undernear a top nav. The CSS fakes it out and loads the tabs with the padding holding it down from the top a bit. This is adjustable for your preference.
- The page reloads. This is not the behavior you typically see in tab controls. Most other tabs use JavaScript to change classes, positions, or both. The tab content therefore appears without the page refreshing. This causes a moment of no content followed by the page jump. That's the price we pay for this method which doesn't rely on JavaScript.
- There is no CSS-only way to ensure that the first tab is "active" when the page loads. There are tricks for making the last tab active. We do have a way to pull the first tab's content to the top, however.
Achieving the Negative Nirvana of no-JS Tabs
First, the bones:
The structure of the tabs is provided by the following BBCode.
[container:phabs]
[h4|phab1][url:#phab1]Tab 1[/url][container:phab-content]Hi, I'm some tab dope[/container][/h4]
[h4|phab2][url:#phab2]Tab 2[/url][container:phab-content]More tab-dope insanity[/container][/h4]
[/container]
Comments:
- You are not required to use heading 4 - any heading will do. The key is to be able to set the target of the anchor link that follows each heading.
- Note that your heading will be downgraded by 1 when it is rendered. E.g., h4 will be automagically turned into h5, so pay attention to your styling. You only get h1-h6.
- Pick heading you aren't using anywhere else. If your theme already styles h2, for example, and you override that styling here, you'll have to spend many more lines of code removing stuff you or your theme added for it everywhere else. The selector chain is specific enough that it won't spill back over into your main theme, but you'll have to change sizes, fonts, etc.
- You should feel free to change the class names and anchors to whatever you like, but avoid built-in bootstrap classes like tab-control, since those will already have styling in the WA main stylesheets and will lead to unpredictable results.
Second, the style-less styles:
Comments are included here, but if you want to use this code, either remove the comments or remove the extra space between the leading / and *. The space is necessary for the comment to show up in this article, but is not valid CSS./ * Just a container to position the tabs within. The min height here tells the browser how much vertical space to clear for the tab control */ .user-css div.phabs { min-height:17em; position: relative; line-height:1; z-index:0; } / * these will be the tabs. The top padding and negative margins are to trick the browser into allowing the tabs to reposition to some distance below the top of the viewport. Inline-block display allows the tabs to float up next to each other */ .user-css div.phabs h5 { display: inline-block; padding-top:100px; margin-top:-100px; margin-right: 0.5em; } / * some styling for the tab links. This is equivalent to the "inactive" tabs. Note that the bottom border is the same style as the tab content border. */ .user-css div.phabs h5 a { color: black; background: #B3A570; padding:0.2em 1em; border: 1px solid #665E40; border-bottom: 2px solid #FFECAC; border-top-right-radius: 10px; border-top-left-radius: 10px; } / * this is the styling for "inactive" tabs */ .user-css div.phabs h5:not(:target) a { border: 1px solid #665E40; border-bottom: none; background: #B3A570; } / * ...and now for the "active" tab */ .user-css div.phabs h5:target a { background: #FFECAC; border:2px solid #a00; border-bottom: 2px solid #FFECAC; } / * here is the content. Note that the min-height here has to accommodate the largest tab's content. You need all the tabs to have the same fixed height because they are absolutely positioned, so they are taken out of the document flow. Other elements won't know how to flow around them. */ .user-css div.phabs h5 div.phab-content { background: #FFECAC; z-index:-2; left:0; top: 1.5em; right:0; height:14em; padding:0.3em; border:2px solid #a00; text-transform: none; font-weight: normal; padding: 5px 10px 10px 10px; border-top-right-radius: 0.5em; overflow-y: scroll; } / * here's our concession to scrollable content: a little style! */ .user-css div.phabs h5 div.phab-content::-webkit-scrollbar { width:5px; } .user-css div.phabs h5 div.phab-content::-webkit-scrollbar-track { background-color:#B3A570; border-top-right-radius: 5px; } .user-css div.phabs h5 div.phab-content::-webkit-scrollbar-thumb { background-color:#A00; border-top-right-radius: 5px; } / * non-targeted tab content position is absolute */ .user-css div.phabs h5:not(:target) div.phab-content { position: absolute; } / * pull the first tab's content to the top */ .user-css div.phabs #phab1 div.phab-content { position: absolute; z-index: -1; } / * pull the targeted tab's content to the top */ .user-css div.phabs h5:target div.phab-content { position: absolute; z-index: -1; }
To-do's
- Would be nice if tab 1 had the "active" color on page load. My research indicates that this can't be done. The :first-child pseudo-selector won't override the :not(:target) selector. I might try something with a section tag and see how that goes. The additional class might work....Stupid workaround: Link to the tab-1 url instead of the page's root url.
- Tabs don't grow with content size because they are absolutely positioned. It would be nice to figure out some workarounds here, rather than just a bunch of trial and error stuff.
Type
Guide, How-to
Looks neat so far, eagerly awaiting more results!
Too low they build who build beneath the stars - Edward Young
Thanks for the love and please feel free to suggest what you'd like to see. We're somewhat limited on making the tab's vertical height change, so I put a styled scroll bar on tab2 to give the feel for what that might look like.
I'm wondering how I'm going to handle giving each tab its own styling, not sure how annoying that will be to do. Scrollbar is nice.
Too low they build who build beneath the stars - Edward Young
Because each tab has its own id (e.g., h4|phab1 has id=phab1) you can style its content by either targeting the h4 header with a straight h4#phab1 { blahblah } or its content div with h4#phab1 div.phab-content { blah blah}. Make sense?
Check, that should do the trick!
Too low they build who build beneath the stars - Edward Young