CUTCODEDOWN
Minimalist Semantic Markup

Welcome Guest
Please Login or Register

If you have registered but not recieved your activation e-mail in a reasonable amount of time, or have issues with using the registration form, please use our Contact Form for assistance. Include both your username and the e-mail you tried to register with.

Author Topic: Need to vent about the CSS attr() function: temptation and frustration  (Read 134 times)

0xdeadbeef

  • Junior Member
  • *
  • Posts: 11
  • Karma: +1/-0
Sometimes, when I work on markup that contains <ol>s, I get really frustrated with the current state of CSS and how vendors don't seem to care in the slightest about supporting actual quality features, instead opting for implementing more and more crazy shit like nesting and layers.

Assume I have an <ol> that requires some very custom counter styles, or has to be inline (e.g. for legal texts, for some reason those guys absolutely love to stuff their paragraphs of ungodly legalese with inline lists, probably to make it all the more difficult to read and comprehend). Either way, simple ::marker customization is out the window, have to roll my own, let's say with ::before.

Ok, no problem. "list-style: none" that bad boy and I'll simply reimplement the numbering, how hard can it be? Well, it can be pretty. Freaking. Hard.

At first I'm thinking like "well, at least I still have the built-in 'list-item' counter", and them I'm like "wait, oh shoot... my <li>s are all displayed inline, so that counter is not incremented". Guess I'll just have to roll my own counter. No problem:
Code: [Select]
ol { counter-reset: myListItem; }...wait, now "start" attributes on my <ol>s don't do nothing. But the solution seems so simple, right? I just need to somehow get that "start" attribute from inside my CSS and do a "counter-set", and I even know a great function that's supposed to be doing exactly that: the attr() function. Well guess what? It doesn't do quack! It only works for "content" properties and doesn't do a goddamn thing in any other context, in any existing browser. Because apparently this functionality would be way too useful and might actually encourage people to leverage semantic markup to write better stylesheets. The spec and MDN docs list many a great feature of this function, too bad that 99% of that functionality exists only in the heads of W3C people and not in objective reality. So what am I supposed to do? Am I supposed to add a
Code: [Select]
style="--start: <start>"to every ordered list with continued numbering like an idiot?

After taking a deep breath, I did find a workaround:
Code: [Select]
ol:not([start]) { counter-reset: myListItem; }It's not a very good one though, because the numbering delves into chaos when nested ordered lists come into play. Even supporting two levels of nested <ol>s would require a hefty amount of convoluted CSS which I'm neither willing to write nor to read.

And that's not even the end of this misery. After that I need to support multiple types of ordered lists: decimals, roman numerals, letters, both upper- and lower-case. Ok, no problem, I do have a "type" attribute, don't I? Should be a breeze to simply select the <ol>s with the necessary [type] and... wait, why have all my 'type="a"' lists became upper-cased??? Oh... it's because the "type" attribute is matched case-freaking-insensitively. But surely there must be a way to force case-sensitive matching, right? I mean, it's 2024 and the technology nowadays is so advanced that it lets people upload literal gigabytes of photos of random garbage while sitting on a crapper, surely a case-sensitive attribute matching is something that would've been implemented ages ago...?
"Hell yeah", the MDN docs exclaim, "there is indeed a modifier that forces the browser into performing a case-sensitive attribute match!" The only problem is that... you guessed it... it's not freaking supported by any existing browser except for Firefox!!!

And don't even get me STARTED on how it's still absolutely impossible to style the freaking <select> dropdowns. I have to start every new project by first implementing a custom select using tons of aria-XXX garbage and writing (ok, copy-pasting from a previous project) couple hundred lines of JS reintroducing stuff like keyboard searching; stuff that works just fine natively, and that I need to reimplement just because I can't give my freaking <option>s a different background color and an occasional icon on the left!

Jason Knight

  • Administrator
  • Hero Member
  • *****
  • Posts: 1052
  • Karma: +188/-1
    • CutCodeDown -- Minimalist Semantic Markup
Honestly if you're screwing around with OL that much, it makes me wonder what the devil you're even doing in the first place. It SOUNDS like something bad. Why can't you use generated content? Is :after or :before really so hard? What are you even doing that would warrant a custom property with it?!?

But then I tell the art-{expletives omitted} pretending to be designers to go plow themselves when it comes to over-styling stuff like SELECT. It's LITERALLY the type of "artist under the delusion they're a designer" BS that has me forcing down the urge to deliver an open handed slap like Will Smith if you talk smack about his wife.
« Last Edit: 22 Mar 2024, 02:08:57 pm by Jason Knight »
We are all, we are all, we are all FRIENDS! For today we're all brothers, tonight we're all friends. Our moment of peace in a war that never ends.

0xdeadbeef

  • Junior Member
  • *
  • Posts: 11
  • Karma: +1/-0
Quote
Honestly if you're screwing around with OL that much, it makes me wonder what the devil you're even doing in the first place. It SOUNDS like something bad. Why can't you use generated content? Is :after or :before really so hard? What are you even doing that would warrant a custom property with it?!?

Seems like you've only just skimmed through my rant and haven't actually read it  :( Using generated content is EXACTLY what I was trying to do, the problem is not generated content or whatever, the problem is that the default "list-item" counter takes care of a lot of things for you, like proper handling of nested lists and respecting 'start' attributes. But if the 'display: list-item' is not applicable to <li>s, that built-in counter does not work since it only increments on 'list-item' <li>s, and one has to reimplement that handling of nested lists and 'start' attributes using a custom counter. And because of lack of support for  'attr()' function in any but the most basic use cases, reimplementing all that becomes such a PITA.

Quote
But then I tell the art-{expletives omitted} pretending to be designers to go plow themselves when it comes to over-styling stuff like SELECT. It's LITERALLY the type of "artist under the delusion they're a designer" BS that has me forcing down the urge to deliver an open handed slap like Will Smith if you talk smack about his wife.

Overstyling is one thing, but just giving the <option>s some basic styling like background color, some border curvature on dropdown and maybe some icons for visual aids seems like pretty basic stuff that should be available out of the box in 2024, no?

Jason Knight

  • Administrator
  • Hero Member
  • *****
  • Posts: 1052
  • Karma: +188/-1
    • CutCodeDown -- Minimalist Semantic Markup
But if the 'display: list-item' is not applicable to <li>s, that built-in counter does not work since it only increments on 'list-item' <li>s, and one has to reimplement that handling of nested lists and 'start' attributes using a custom counter. And because of lack of support for  'attr()' function in any but the most basic use cases, reimplementing all that becomes such a PITA.
The WHAT now? That's utter gibberish. It increments when you counter-increment which can be done on any element -- or not done for that matter. In no way, shape, or form is it tied to the parent tag or child where you're incrementing it.

Do you have example code of something akin to what you're talking about, because it really does sound like you don't even know how CSS counters work. Or are missing some essential part of actually leveraging selectors.

Especially since I have no clue what the devil attr() even has to do with any of this.

Wait, is your entire complaint that you have to make a new counter name when they're nested? Oh noes, teh horrurz.
We are all, we are all, we are all FRIENDS! For today we're all brothers, tonight we're all friends. Our moment of peace in a war that never ends.

0xdeadbeef

  • Junior Member
  • *
  • Posts: 11
  • Karma: +1/-0
Quote
The WHAT now? That's utter gibberish. It increments when you counter-increment which can be done on any element -- or not done for that matter. In no way, shape, or form is it tied to the parent tag or child where you're incrementing it.

Do you even read the posts you reply to? I'm not talking about ANY counter, I'm talking about the SPECIAL BUILT-IN 'list-item' counter. https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_counter_styles/Using_CSS_counters#list_item_counters Literally the first sentence in the docs. You don't need to counter-increment the built-in counter because IT DOES THAT AUTOMATICALLY. Now do you know HOW it does that? Well it does that by incrementing not on just any tag and not on just any <li> tag, but only on <li> tags that HAVE DISPLAY: LIST-ITEM APPLIED TO THEM. Which means that if those <li>s have their display properties set to anything else, like inline or flex or whatever, THAT COUNTER IS NOT INCREMENTED.

Quote
Do you have example code of something akin to what you're talking about, because it really does sound like you don't even know how CSS counters work. Or are missing some essential part of actually leveraging selectors.

Knock yourself out:

HTML:
Code: [Select]
<ol start="3" class="inline">
  <li>List item 1</li>
  <li>List item 2</li>
  <li>List item 3</li>
</ol>

<ol class="inline">
  <li>List item 1</li>
  <li>List item 2</li>
  <li>List item 3</li>
</ol>

<ol start="3">
  <li>List item 1</li>
  <li>List item 2</li>
  <li>List item 3</li>
</ol>

<ol>
  <li>List item 1</li>
  <li>List item 2</li>
  <li>List item 3</li>
</ol>

CSS:
Code: [Select]
ol.inline, ol.inline li {
  display: inline;
}

Now let's see your solution for adding ::before counters for these lists, so that the "start" attribute, if present, is also respected. Let's also see how well it goes for you to use the built-in "list-item" counter.

Man, as a long-time reader of yours, I'll say this: you're really smart most of the time and I've learned and continue to learn a great deal from you, but sometimes you really just talk out of your arse.

Jason Knight

  • Administrator
  • Hero Member
  • *****
  • Posts: 1052
  • Karma: +188/-1
    • CutCodeDown -- Minimalist Semantic Markup
Sorry, I don't know if it was language barrier, or terminology differences, but I really wasn't picking up what you were putting down. I think that you were talking about list-counter as if it were a CSS counter is where I got lost in the forest. CSS doesn't see nor does it even care about the value used automatically on LI.

The code sample helps. Always does... though I'm still not sure I'm following along 100% on what you even mean.

Are you talking about how attr() returns string, but counter-reset / counter-set requires a number or integer? (I still don't know why -set and -reset are two separate declarations, they operate identically)

If so, yeah that's a pain. And yes, the only "real' workaround right now is to set a custom property in an inline-style as you said... which... yeah. Kinda dumb... but at least you're conveying information about what it is, not what it's supposed to look like. A painfully small consolation...

Honestly, that inline-style in your initial post should have told me what you were talking about... but without the markup it applies to it just turned to gibberish to my brain.

Thing is the fix is allegedly coming, but honestly it's something that shouldn't NEED to be fixed. I mean if the JavaScript engine in the browser can handle "String 3" and "Number 3" being the same thing for loose assignment, what's CSS' gripe?

But the syntax that may someday work if it ever leaves the experimental is:

counter-reset: myListItem attr(start integer);
and/or
counter-reset: myListItem attr(start number);

As to which of those will -- someday maybe? -- actually fix this "problem"... your guess is as good as mine.

Sadly public browser support is bupkis, the places it is supported locked away behind configuration flags.
https://caniuse.com/mdn-css_types_attr_type-or-unit

Is that what you're referring to?

Also I hear you on how they keep implementing syntactic sugar like the derpy 'nesting" trash or endless pointless artsy-fartsy colourspaces no legitimate website should have any need of... but are dragging their heels on stuff that might actually do things like make formatting and creating layouts easier.

You know, it's kind of funny. CSS is the perfect example of where typecasting is an enemy, not a friend.
« Last Edit: 25 Mar 2024, 07:11:04 am by Jason Knight »
We are all, we are all, we are all FRIENDS! For today we're all brothers, tonight we're all friends. Our moment of peace in a war that never ends.

Jason Knight

  • Administrator
  • Hero Member
  • *****
  • Posts: 1052
  • Karma: +188/-1
    • CutCodeDown -- Minimalist Semantic Markup
Also though, what type of legal content would have inline lists? Are you talking sentence/sectional notation akin to that used in scripture?

If so, lists might be the wrong tags entirely. In fact, the correct tag might be an anchor with the number inside it and a hash link. That's how I'd handle a biblical passage like Matthew 6 : 5-6

Code: [Select]
<p>
  <a href="#matthew_6_5">5</a>And when you pray, do not be like the hypocrites, for they love to pray standing in the synagogues and on the street corners to be seen by others. Truly I tell you, they have received their reward in full.  <a href="#matthew_6_6">6</a> But when you pray, go into your room, close the door and pray to your Father, who is unseen. Then your Father, who sees what is done in secret, will reward you.
</p>

Grammatically it's still a paragraph, it just has anchors/notations for each verse. I've seen people try to use inline lists for that, and it's an utter shit-show.

And using hash link anchors has the bonus those subsections are hotlinkable.
« Last Edit: 25 Mar 2024, 07:19:30 am by Jason Knight »
We are all, we are all, we are all FRIENDS! For today we're all brothers, tonight we're all friends. Our moment of peace in a war that never ends.

0xdeadbeef

  • Junior Member
  • *
  • Posts: 11
  • Karma: +1/-0
Quote
Are you talking about how attr() returns string, but counter-reset / counter-set requires a number or integer? (I still don't know why -set and -reset are two separate declarations, they operate identically)

If so, yeah that's a pain. And yes, the only "real' workaround right now is to set a custom property in an inline-style as you said... which... yeah. Kinda dumb... but at least you're conveying information about what it is, not what it's supposed to look like. A painfully small consolation...

Yes, exactly! Although I'm now confused about the actual underlying cause of attr() not working for this particular use case. I thought that it was because the attr() function is only currently implemented for "content" properties, ala "content: attr(whatever);" (this is what the MDN docs state, at least), but you're saying that the real problem here is type mismatch and the lack of support for type casting? I guess this question could be reformulated in a more constructive way: is there any other property apart from "content" for which the string-typed attr() function would work in modern browsers?

Quote
Also though, what type of legal content would have inline lists? Are you talking sentence/sectional notation akin to that used in scripture?

I'm not exactly sure to be honest. The actual text goes something like this: "We may collect personal data about: a) this, and b) that, and c) whatever else we desire." It looks like a semantic list to me, but, as you correctly guessed, there is a bit of a language barrier and I know next to nothing about intricacies of English legal texts structuring. Is there some sort of rule-of-thumb that can be used to differentiate between actual semantic lists and the sectional notation from your example?

On a related note, another type of content I come across fairly regularly is a paragraph of text that ends with a semicolon and is followed a list of things that paragraph is about. I always struggle to find the correct markup for such content. The obvious would be:

Code: [Select]
<p>Some rather lengthy paragraph that is related to the following list of things:</p>
<ul>
  <li>This</li>
  <li>That</li>
</ul>

But the text inside the <p></p> would not be a complete thought without the list though, so it shouldn't be a <p> then?

Jason Knight

  • Administrator
  • Hero Member
  • *****
  • Posts: 1052
  • Karma: +188/-1
    • CutCodeDown -- Minimalist Semantic Markup
Yes, exactly! Although I'm now confused about the actual underlying cause of attr() not working for this particular use case. I thought that it was because the attr() function is only currently implemented for "content" properties, ala "content: attr(whatever);" (this is what the MDN docs state, at least), but you're saying that the real problem here is type mismatch and the lack of support for type casting? I guess this question could be reformulated in a more constructive way: is there any other property apart from "content" for which the string-typed attr() function would work in modern browsers?
It's kind of a confusing mess really. The big thing is that attr() also works if you put it into a variable, and then put that variable onto the content attribute. If attr() were locked to content only, that wouldn't work.

And there's another "rub" to it. This doesn't work:
Code: [Select]
--test:3;
content:var(--test);

But this does.
Code: [Select]
--test:"3";
content:var(--test);

This doesn't work:
Code: [Select]
--test:"1rem";
padding:var(--test);

But this does:
Code: [Select]
--test:1rem;
padding:var(--test);

Thus it's a typecasting issue, NOT specific to attr(); Attr() seems to return what getAttribute would in JS, a string. That's why attr() "needs" to have those typecasts added.

But let's say you had:

<div id="test" data-value="2em">

and
Code: [Select]
#test {
  padding:attr(data-value);
}

That doesn't work. What the proposed / experimental feature does to "fix" that is to add typecasting. The markup becomes:

<div id="test" data-value="2">

And the CSS is:
Code: [Select]
#test {
  padding:attr(data-value em);
}

Theoretically, someday, that will work. Allegedly. Don't hold your breath.

But the real rub is I can't think of any property other than content that accepts a string. But yes they are planning to add typecasting attr() to "fix" these issues. Why they couldn't just go "oh hey this is a string, maybe we should parse it for type juggling" escapes my understanding.

The actual text goes something like this: "We may collect personal data about: a) this, and b) that, and c) whatever else we desire."

Honestly inline like that, they're no longer "grammatical bullet points" and I'd leave it alone with no extra markup. That's really treading into diminishing returns.

Is there some sort of rule-of-thumb that can be used to differentiate between actual semantic lists and the sectional notation from your example?
The question is are you adding "formatting" for a grammatical or structural reason. In the case of your "abc" example there is no grammatical / structural reason for that formatting because there is no formatting... so leave it be.

At least, that's how I like to think about it.

A good way to self-check yourself on that though? Read the page with your CSS style disabled/removed. Does it still make sense and match how the writer created/wrote it. If the answer is no, you're using the wrong markup.

BUT down into the nitty-gritty like this you're right. Figuring out whether or not to even add markup is confusing and at times quite arbitrary.

But the text inside the <p></p> would not be a complete thought without the list though, so it shouldn't be a <p> then?
A great example of where it gets rather questionable... but in that specific example I wouldn't use a <p> there at all IF everything retained the block style layout. (aka you don't set inline on the list/list-items). I would be tempted to make it a numbered heading and a list... as the text before the list describes said list. Or I'd break it into a heading, paragraph, and list inside a SECTION or ARTICLE.

But that's where you have to ask: "Am I overcomplicating this?"
We are all, we are all, we are all FRIENDS! For today we're all brothers, tonight we're all friends. Our moment of peace in a war that never ends.

0xdeadbeef

  • Junior Member
  • *
  • Posts: 11
  • Karma: +1/-0
Quote
A great example of where it gets rather questionable... but in that specific example I wouldn't use a <p> there at all IF everything retained the block style layout.

Aha, so even you sometimes make trade-offs between semantic markup and layout/styling :) Frankly I thought you were a die-hard semantic markup purist :D

I mean, obviously, the ultimate goal of all this is to deliver content to as broad an audience as possible, and proper markup is just a means to that end. I've only been practicing your way of doing things for about 2 years so far, and most of the time these changes are met with A LOT of resistance from other devs and designers, but what I love about the whole semantic markup thing is that it establishes a clear "content --> markup --> styling" path that serves sort of as a "framework"; and, as opposed to "real" web frameworks, its core idea is actually rational and allows me to reason about my markup, styles and overall program structure in a completely different way, while at the same time cutting down the amount of code I need to write by orders of magnitude.

So, even though I understand that sometimes that path needs to be walked backwards (i.e., sometimes one has to add some non-semantic stuff like extra <div>s and <span>s for styling purposes), it's still not the same thing as actually choosing the markup based on layout considerations. Doesn't it sort of go against the whole semantic markup idea?

Jason Knight

  • Administrator
  • Hero Member
  • *****
  • Posts: 1052
  • Karma: +188/-1
    • CutCodeDown -- Minimalist Semantic Markup
It's not a trade-off when you're looking at WHY HMTL semantics exists. A great example of this is <b>, <i>, <em>, and <strong>. There are grammatical and structural reasons you would have text that's bold or italic other than emphasis and "more emphasis". A book title not being cited for example would be italic in a professionally written document. Not as a presentational affectation, but to convey meaning. Just as one might put it in single quotes when handwriting it or on an old-school typewriter that can't do italic. Just as a entity or party in a legal document would be bold, or underscored when handwritten. That's what <b> and <i> are for. They don't mean "show this text as bold or italic" they mean "would be bold or italic to help convey meaning".

If you're writing those a>b>c sections inside a paragraph, there is not extra formatting or meaning you would convey when writing it out. Thus it would not nor should get extra markup.

Block formatting is also a form of grammatical structure. If they are meant as significant bullet points or selections, writing them inline in a paragraph or even just presenting them that way is wrong. Even if the author claims otherwise.
We are all, we are all, we are all FRIENDS! For today we're all brothers, tonight we're all friends. Our moment of peace in a war that never ends.

0xdeadbeef

  • Junior Member
  • *
  • Posts: 11
  • Karma: +1/-0
Is there a book or something you might recommend where one could learn about professional document writing, grammatical structure etc? inb4 "we boomers learned this stuff in kindergarten" :D (I do recall you saying something like this in your articles). Because I've never even thought about block formatting as a form of grammatical structure, even the notion of a BFC is something CSS is concerned with, not HTML. And believe it or not, they don't really teach you this in schools, at least not in the last 20 years and not where I come from. I'd like to be able to destroy my opponents by bashing professional document editing rules against their heads as efficiently as you do :) On a more serious note, it looks like, if you remove all the fancy presentational "artsy-fartsy" stuff from the web and concentrate purely on HTML, and treat a website as an actual document, then you can't really become good at it without actually being a professional document writer, which is something they most definitely don't teach you anywhere, not on MDN, not on any programming-related resource.

And while we're on the subject -- do you have a personal take on TeX/LaTeX for writing (I know you do :) )? I've been playing around with it lately for my own little math-related book; however, in my university, even though I majored in physics, they never taught us to properly use TeX, not even for writing research papers. So I started with LaTeX, and although I enjoyed being able to typeset documents in a programmatic way, overall I got highly mixed feelings about it, mostly because it's such a PITA to customize visual appearance of ToC, headings etc. in ways that LaTeX authors didn't have in mind. Plain TeX, on the other hand, lets you do whatever you want, however it is such a low-level intricate assembly language that it doesn't seem feasible to use it for typesetting real-world documents.

 

SMF spam blocked by CleanTalk

Advertisement