CSS solution: child boards in columns on default markup.

Started by Antechinus, June 14, 2020, 10:34:33 AM

Previous topic - Next topic

Antechinus

Here's a trick I just thought up when I was doing too much CSS. :D

The old "tidy child boards" thing of arranging large numbers of child boards in columns is not hard to do in principle. You just set the links to float: left; or display: inline-block; and add a suitable fixed width to them.

However, getting a clean result on default 2.0.x markup is a PITA because there is a stray colon after the "Child Boards" text, and there are stray commas after each link. These grotty little pieces of crud aren't HTML elements as such, so cannot be targeted by CSS. This means they hang around looking stupid in all the wrong places when you try to set your board links up in columns. :P

The sneaky idea I just came up with is to hide the horrible things with ::after pseudo elements set to position: absolute; This works perfectly and is not hard to set up. As a test case I used the Language Specific Support board on this site, which has more child boards than a junkyard dog has fleas. The CSS looks like this:

#board_12_children strong:first-child {
display: block;
}
#board_12_children td>a {
position: relative;
display: inline-block;
width: 32%;
line-height: 2.2rem;
}
#board_12_children td>a:first-of-type {
margin-left: -5px;
background-color: #14171B;
}
#board_12_children td>a::after {
position: absolute;
display: block;
top: 0;
left: 100%;
width: 4px;
height: 2.2rem;
background-color: #14171B;
content: '';
}


The first chunk of code makes the bold "Child Boards" text stand on a line by itself, which is the neatest and easiest for this arrangement.

The second chunk allows setting a defined width on the links, and allows setting the necessary pseudos to absolute.

The third chunk uses a background colour that matches the parent table cell, along with a negative left margin, to hide the stray colon that is usually after the  "Child Boards" text. With the title set to its own line, the colon gets bumped to in front of the first link, so you want it hidden. This does the trick (note that the colour matches the theme I'm working on, so adjust to suit your theme).

The fourth chunk of code is the clever bit. The pseudo elements are set to the matching background colour for the parent table cell. Being absolute positioned they overlap content that follows them, much like a drop menu. They're sized to match the line height of the links and just wide enough to cover the stray commas. Setting them to left: 100%; means their left edges are right at the end of each link, so they poke out past the link and over the comma you want to hide.

The result looks like the screenshot.

Naturally I'm now wondering why I didn't think of this years ago. :D

Decent_946

Looks clean. I'd actually like it to be implemented in this site. :P
Thankx to RebellioN

Arantor

The only downside (and the reason I didn't do it this way in Tidy Child Boards) is that it has one problem.

Namely, the board order is wrong in my mind.

You get the boards ordered as:

A B C
D E F
G H I

Rather than what I wanted:
A D G
B E H
C F I

Of course this is also doable in CSS these days but that was 10 years ago when browsers were stupider :P

Antechinus

Yes I get that you could use tricks to get them running down columns instead, but offhand I think that's only doable with flex, and l wasn't sure if setting that table cell to flex would bork something. Didn't feel like a long testing string around midnight. ;)

Anyway, after spending a bit doing all that trickery, I figured out a simpler solution. Amazing how often this happens when I'm going to sleep. :D Will post the simpler solution as soon as I'm coffee'd up enough to check it works.

Arantor

column-count is a thing if you're careful and make each item in it a table or a block so it doesn't get split across columns.

Antechinus

#5
Ok, one simpler solution coming up. As a bonus, it also deals with something I forgot to take account of around midnight last night. :P

The thing I forgot to take account of is that when there are new posts in a child board, the usual board link has another link next to it, with the new.gif inside that. This means simply setting all links to 32% will bork the layout. Fortunately the default markup wraps both of these links in a strong tag, so you can use that to deal with this situation. :)

So, the even clever than before because it will work all the time code goes like this:

#board_12_children td {
color: transparent;
}
#board_12_children td>a,
#board_12_children td>strong {
display: inline-block;
width: 32%;
line-height: 2.2rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
#board_12_children td>strong:first-child {
display: block;
}
#board_12_children td>a:first-of-type,
#board_12_children td>strong:nth-of-type(2) {
margin-left: -6px;
}
.children .new_posts + a {
position: relative;
bottom: -2px;
}


Taking that from the top: the d'oh moment was when I remembered that links and strong tags have their colours defined in the CSS, so will be unaffected if the parent td is set to color: transparent. This hides the unwanted punctuation without affecting the bits you want to keep, so no pseudo elements and no background colours are required.

And that one is so basic I should have thought of it in 2007. ::) Moving right along...

The next chunk is the basic width and display settings for the columns, but set to only target elements that are directly inside the parent td. This is important for dealing with new posts.

The next two chunks are the other basics: set the "Child Boards" title on its own line, and haul the first whatsit in the columns left to compensate for that colon you can't see any more.

The last chunk is a little tweak for the height of the default new.gif. It wants to sit too high, so hauling it down a pixel or two makes it look a lot better.

So use this instead of the stuff in the OP. This is better. :)

(Although nifty tricks with pseudo elements can be very handy, so the same principles as in the OP can be useful elsewhere. Just don't bother with them for setting child boards in columns.)

ETA: Added some white-space/overflow tricks to Chunk #2, for extra insurance. ;)

Antechinus

#6
Quote from: Arantor on June 14, 2020, 08:30:22 PM
column-count is a thing if you%u2019re careful and make each item in it a table or a block so it doesn%u2019t get split across columns.

Tried CSS columns. Doesn't appear to be supported by my browser. Tried it with and without the -moz- prefix. Didn't work either way.

ETA: Aha! CSS columns only work on block level elements, so to get it to work inside table cells you'd have to change them from their default display: table-cell; to display: block;

That's doable on a tabular board index, but it ends up requiring quite a few shenanigans to deal with the whole kaboodle once you start breaking various bits out. It's the sort of thing I could happily do on a custom theme (like the infamous Mutant) but it's a bit over the top for a basic site override of the default theme child boards. :)

And before anyone suggests it: no, you can't use flex here either. Not without breaking the entire table. More shenanigans required there too.

Bloc

Tables are not to be used for layout purposes. Hm, that sentence sounds familiar.. :D Seriously, exchanging boardindex table with *any* other markup should be the first you do before changing its layout..and then you can simply erase the colon right inside the template anyway.

But great creativity about masking things if you are not willing to do that, especially about the transparent color..lol, that is a real "doh" moment. :) (as a sidenote, there are umpteen other colons associated with "pages" in many SMF 2.0 templates, so if one wants to get rid of those, even the "pages" word itself, thats also a scratch-your-head in everyday SMF theme making)

Antechinus

Tell me about it. :D The markup for the pages crud isn't even consistent. I've been looking at that, trying to think of what can be done with it (short of attacking the template with a chainsaw again).

This dodge was invented because at the moment I'm experimenting with making dark themes that people can run live on this site via Stylus/Stylem. That means no markup changes allowed, so I have to get cunning. ;)

Antechinus

Oh yeah, latest experiment: icons. Again, for running live via a browser add-on.

The on/on2/off/redirect icons are a little tricky to replace, because there are no classes associated with the different icons, so you can't target via the parent element or an image class. The only way of picking up which image is in play is by targeting bits of the img src. You could use title or alt text, but they are the same for on and on2, so if you want to differentiate between those it's img src or nothing.

So you can get your CSS to figure out which image it has to replace. Now to replace it with something else. Can't be done with a pseudo, because that hangs off the parent anchor, and there is no way of going parent > img src > ::after pseudo in CSS. Simply will not work.

However, you can (weirdly enough) put a padding and a background image on an image. That's as easy as putting a padding and an background image on anything else. And, since your CSS targeting is via img src, the CSS can know which image you want to have which background. So the next cunning trick goes like this:

1/ Set your board icon anchors to a fixed height, with hidden overflow.
2/ Set your original board icon images to have a bottom padding 1px greater than the height of the parent anchor.
3/ Now use the relevant chunk of the icon's img src (on.png/on2.png/off.png/redirect.png) to call the right background image for each icon.
4/ Set the position of the background image to 50% 100% and set repeat to no-repeat.

/* Cunning on/off icon replacement. */
.table_list .icon a {
display: block;
max-height: 41px;
max-width: 41px;
overflow: hidden;
margin: 0 auto;
border-radius: 6px;
}
.table_list .icon img {
height: 41px;
width: 41px;
margin-top: -42px;
padding-bottom: 42px;
background-position: 50% 100%;
background-repeat: no-repeat;
}
.table_list .icon img[src*="on.png"] {
    background-image: url("file:///B:/VertrigoServ/www/Vanilla_20x/Themes/Prince_of_Darkness_201/images/on.png");
}
.table_list .icon img[src*="on2.png"] {
    background-image: url("file:///B:/VertrigoServ/www/Vanilla_20x/Themes/Prince_of_Darkness_201/images/on2.png");
}
.table_list .icon img[src*="off.png"] {
    background-image: url("file:///B:/VertrigoServ/www/Vanilla_20x/Themes/Prince_of_Darkness_201/images/off.png");
opacity: .5;
}
.table_list .icon img[src*="redirect.png"] {
    background-image: url("file:///B:/VertrigoServ/www/Vanilla_20x/Themes/Prince_of_Darkness_201/images/redirect.png");
}


Voila. The old images are still there, and their title and alt text attributes work just like they always did, but you can't see the old images anymore. Visually, they are now replaced with shiny new ones that you like better. The shiny new ones can be called in from your desktop/device, or can be done directly in the CSS as base64 strings of horrible poo five miles long, or they can be called in from any handy folder of icons you have stashed online. Any of those methods will work.

In principle this will work with any image. The only catch is you require a handy parent element, that can use hidden overflow to hide the bits you don't want to see.

Screenshot shows code running live on this site via Stylem. :)

PS: The only reason I bothered to set a width and a border-radius on the anchors is that the test icons were made for my old Prince of Darkness theme, and they are square with an almost black background (ie: no alpha channel). That didn't sit well on the test theme background, so I matched the limits of the anchor to the shape of the icons sans black background. If using icons made for the theme in question you could skip this, since you could just make them with alpha where you wanted it.

Bloc

Ingenious :)

Being able to target title and even src is a great leap forwards in css, no doubt. Ironically, the thoughts about semantic markup we had in 2010 for SMF - which ultimately had to be downsized to make sensible layouts out of what css could do then(+ supporting IE6 and'all(..)) - are now actually 100% true. Because it does not matter anymore what markup you use, well, apart from the elephant table in the room of course. :D 

Antechinus

Yes the advances in targeting are really rather wonderful. It's like having smart bombs instead of dumb ones.

I am coming around to thinking that tables are actually fine for a lot of things. For example, back when I wrote my old memberlist mod I rewrote that function in the template to get rid of the table. That's fine for sighted users, since they just want the eye candy of the separate blocks for each member. OTOH, anyone on a screen reader will probably prefer the original markup, because on a screen reader it makes more sense. The table headers are marked up with scope="col", so screen readers can keep track of things nicely. It would probably be even better if the markup included extra th's with scope="row", but as it is it's still better than the rewritten template (which is just divs and lists).

So, when doing the latest Mutant Curve I kept the default tables for the memberlist and who's online (as well as for the board index, message index, unread, etc) and used CSS to alter the presentation to make it responsive. This was the big problem back in the "don't use tables" days: everyone though tables could not be made properly responsive. As it turns out, they can. It's not even that difficult. The average user won't give a damn about the markup, but screen reader users will probably want it tabular, providing the tables are marked up to make them easy to use on a screen reader.

Bloc

True. But I will argue that boardindex is not a table because of the way we read and perceive it. The boards can be seen as rows with its info(stats,description, last post etc) as columns..but we do not sort on anything else than the boardnames, aka the rows..which makes the boardindex more a list of boards rather than a table of boards. Not to mention that there is a parent grouping in the form of categories.

Do screen readers actually favor tables? Seems its more important to distinguish the various elements from each other by using correct tags?

Arantor

I would have to argue that semantically it's actually a list, or collections of lists with properties.

Gwenwyfar

Quote from: Bloc on June 15, 2020, 12:15:07 PM
Ingenious :)

Being able to target title and even src is a great leap forwards in css, no doubt. Ironically, the thoughts about semantic markup we had in 2010 for SMF - which ultimately had to be downsized to make sensible layouts out of what css could do then(+ supporting IE6 and'all(..)) - are now actually 100% true. Because it does not matter anymore what markup you use, well, apart from the elephant table in the room of course. :D 
I believe that is possible since CSS 2, if I'm not mistaken. MediaWiki has long since used it to make a link show a different image according to link ending, or something like that. Or, that's as far back as I recall seeing this being used, anyway.

Css can do more tricks than many realize and some "new" tricks could have been used as far back as IE6 if someone had figured it out back then.

No different than most things, really.

Bloc

Browser support were a bit random back then and since SMF was supposed to support any old browser it wasn't much of a choice - even if it existed.

Gwenwyfar


Antechinus

So here's another thing with doing a dark theme: bloody BBC coloured text. People love using all sorts of colours which look fine on a light background, but which will either burn your eyes out or be almost invisible on a dark background. This was always one of my pet hates back when I was an admin trying to support a range of themes, to the point where I simply disabled coloured text*.

It would be possible to forcibly disable coloured text via CSS running in Stylus/Stylem, or in a theme's index.css. You'd simply use something like this:

span[style*="color"]{color: #standard_body_text_colour !important;}
That would nail the lot and turn them all into the default colour for body text, so they matched all posts and sigs, but is no good if you want to allow colours. This is another case where CSS filters can be handy. There are 15 default colours in the standard 2.0.x dropdown, and hopefully the most annoying members won't realise they aren't actually restricted to these 15.

I've played with a few of these colours (that were visible in various people's sigs) and on a background of #14171B the following adjustments make for good color balance:

span[style="color: red;"] {filter:brightness(.6);}
span[style="color: limegreen;"] {filter:brightness(.7);}
span[style="color: blue;"], span[style="color: purple;"] {filter:brightness(1.2);}
span[style="color: navy;"] {filter:brightness(1.8);}

Obvious next question: what do you do with black if someone is bonkers enough to use that? The default group colour for the server team on this site is black. Oh hey, can we haz dark theme on smf.org? Err, yeah. Can't use a brightness filter on black, because black by definition has no brightness, so 999 x 0 still = 0. U R screwed on brightness. :P However, an invert filter works pretty well. It's obviously not black anymore, but at least you can read it.

a[style="color: #000000"] {filter:invert(.4);}
And yes, the group colours use a different syntax to the BBC dropdown colours, just for added giggles. Anyway, point is that by tweaking these pestilential mongrels you can make them behave on any background, providing you have the patience to throw enough CSS at them. :)


*In practice, I found that it was generally used by the most annoying members anyway. You know, the sort that insist on entire paragraphs in different brain-frazzling colours, along with copious use of caps and exclamation marks. Those members. So, forcibly making them less annoying suited everyone else. :D

Antechinus

#18
Hey here's a fun party trick. Scroll bars on dark themes are always pox. I was using a background of #191D21 for BBC code boxes. Looked fine, apart from the scroll bars when they kicked in. They burn your retinas out with a dark theme, at least on Windows 10.

The handy thing here is that 2.0.x always marks them up as .codeheader + pre > code, so that's bulletproof targeting that won't accidentally nail any other pre or code elements that happen to be lurking anywhere else in SMF. This means you can use styling on the pre to do a couple of tricks.

Setting the pre to position: relative; allows absolute positioning of ::before and ::after pseudo elements. If the ::before is set to z-index: 1; both pseudos can be made to overlay the scroll bars, and can be set to any colour or gradient of any chosen opacity. If using flat colours, the two pseudos can simply be butted up to one another in the bottom right corner. Gradients screw up there unless you use a 45 degree skew transform on both pseudos and hidden overflow on the parent pre, which allows perfect gradient matching in the corner.

The slight catch is spacing to the perimeter. There's a bug on Windows 10 with Pale Moon (suspect it would be the same in Firefox and all derivatives, but haven't tested yet). Even if you set enough padding on the code box to allow for the height of the pseudo across the bottom, the last line of code will be hidden behind it when there is a vertical scroll bar but no horizontal scroll bar. IOW, the code runs to the bottom of the box, as if there was no bottom padding. It's not necessarily a fatal flaw (providing pseudo opacity isn't too high) but it'd be better to have clearly visible code right to the bottom. The other potential problem is varying scroll bars widths across different browser/OS/device combinations. You'd have to figure out which one was going to be the widest, and size the pseudos for that.

Code behind it is this:

/* A code block - maybe PHP ;). */
.codeheader + pre {
position: relative;
overflow: hidden;
margin-bottom: 1rem !important;
border: solid #45505C;
border-width: 2px 0;
}
.codeheader + pre::before, .codeheader + pre::after {
position: absolute;
display: block;
top: -8px;
right: 0;
bottom: 8px;
width: 17px;
background: linear-gradient(to right,rgba(25,29,33,.65),rgba(25,29,33,.9));
content:'';
pointer-events: none;
transform: skewY(45deg);
}
.codeheader + pre::before {
z-index: 1;
top: auto;
right: 8px;
bottom: 0;
left: -8px;
width: auto;
height: 17px;
background: linear-gradient(rgba(25,29,33,.65),rgba(25,29,33,.9));
transform: skewX(45deg);
}
code.bbc_code {
margin: 0;
padding: 11px 19px 15px 7px;
background: #191D21;
color: #959DA4;
font-size: 1.1rem;
line-height: 1.7rem;
border: 0;
}


The bottom margin on the pre is only declared as !important because (for some weird reason) SMF 2.0.x has an inline style there which sets a margin of 0. With the pseudos set on the pre, any borders and margins are easiest if put on the pre too, so it's necessary to override the inline style. You also have to set pointer-events: none; on the pseudos to make them transparent to user actions, so the scroll bars work normally.

Screenshot attached. :)

ETA: Just thought of a fix for that slight bug. D'oh. Another pseudo, this time inside the code box itself. It won't affect any actual code there, but it forces the correct bottom spacing at all times, regardless of what the scroll bars are doing.

code.bbc_code::after {
display: block;
height: 17px;
content:'';
}


With this you use the pseudo to set the bottom padding in the code block, and would skip the bottom padding shown earlier. Apart from that the previous code is still fine.

Gwenwyfar

Quote from: Antechinus on June 19, 2020, 05:41:19 PM
So here's another thing with doing a dark theme: bloody BBC coloured text. People love using all sorts of colours which look fine on a light background, but which will either burn your eyes out or be almost invisible on a dark background. This was always one of my pet hates back when I was an admin trying to support a range of themes, to the point where I simply disabled coloured text*.

It would be possible to forcibly disable coloured text via CSS running in Stylus/Stylem, or in a theme's index.css. You'd simply use something like this:

span[style*="color"]{color: #standard_body_text_colour !important;}
That would nail the lot and turn them all into the default colour for body text, so they matched all posts and sigs, but is no good if you want to allow colours. This is another case where CSS filters can be handy. There are 15 default colours in the standard 2.0.x dropdown, and hopefully the most annoying members won't realise they aren't actually restricted to these 15.

I've played with a few of these colours (that were visible in various people's sigs) and on a background of #14171B the following adjustments make for good color balance:

span[style="color: red;"] {filter:brightness(.6);}
span[style="color: limegreen;"] {filter:brightness(.7);}
span[style="color: blue;"], span[style="color: purple;"] {filter:brightness(1.2);}
span[style="color: navy;"] {filter:brightness(1.8);}

Obvious next question: what do you do with black if someone is bonkers enough to use that? The default group colour for the server team on this site is black. Oh hey, can we haz dark theme on smf.org? Err, yeah. Can't use a brightness filter on black, because black by definition has no brightness, so 999 x 0 still = 0. U R screwed on brightness. :P However, an invert filter works pretty well. It's obviously not black anymore, but at least you can read it.

a[style="color: #000000"] {filter:invert(.4);}
And yes, the group colours use a different syntax to the BBC dropdown colours, just for added giggles. Anyway, point is that by tweaking these pestilential mongrels you can make them behave on any background, providing you have the patience to throw enough CSS at them. :)


*In practice, I found that it was generally used by the most annoying members anyway. You know, the sort that insist on entire paragraphs in different brain-frazzling colours, along with copious use of caps and exclamation marks. Those members. So, forcibly making them less annoying suited everyone else. :D
Cool :)

Advertisement: