Hacker News new | past | comments | ask | show | jobs | submit | more criswell's comments login

I know it's going to be abused to hell like everything popular but definitely a useful power tool.

It'll be really nice for container queries when they're ready. Something like: `wider-than-[500px]:hover:text-red-500` and so on.

Also super nice for `:has` (although ordering is a concern at the moment): `[:has(:invalid)]:bg-red-500`.


You can't get punched in the mouth on the internet.


There's `space-y-N` which does exactly this, `space-x-N` for horizontal.


If you want to change the padding in a project that's using Tailwind you only need to look for classes that begin with `p` followed by a letter for a side or x and y for an axis (same is true for margins). Those are by far the most cryptic classnames and by the time you finish reading this sentence you got it.

In a project where you have to name everything semantically you don't know where the hell the padding is going to be.

It's amazing for long term maintainability and quick prototyping. There is a lot of value in classes that does one thing well.

Been wrinting CSS for 15 years, switched to Tailwind 2 years ago, just for reference.


Yeah, but humans.


You're changing the source order doing this which can get messy plus generating a lot of long selectors. Example:

  .m4, .profile-card, .other-card,
  .header, .foo, blah {
    margin: 4em;
  }


This is how you can do all of that:

  class="hover:red" -> .hover\:red:hover { color: red }

  class="before:red" -> .before\:red::before { color: red }

  class="medium:red" -> @media (min-width: 500px) { .medium\:red { color: red }
The important thing though is it doesn't need to be used for everything. I think it makes a lot of sense for structural stuff. When you dig into like, children of a hovered element I can see it getting a little messy.


How come people who do this only ever use class names? Why not invent your own data attribute like data-hover="red" where you create new namespaces for things like hover, or pseudo classes, why it it always only ever class names?


Totally talking without thinking about it too much here:

The classList API makes modifications to the class property very easily.

You'd be essentially limited to one identifier in attribute selectors. You can't really select from multiple identifiers with a data attribute without doing like:

  [data-hover*="foo"]
which would search for "foo" anywhere in the attribute, which could mean incorrect substring matches.

Chaining attribute selectors would be rough too:

  [data-hover*="foo"][data-hover*="bar"] {}
vs

  .foo.bar {}


> The classList API makes modifications to the class property very easily.

So does the dataset interface for custom data attributes: https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement...

> You'd be essentially limited to one identifier in attribute selectors. You can't really select from multiple identifiers with a data attribute…

That's just not true, there's an attribute selector that targets strings in a whitespace separated list: [attr~=value], so you could think of .demo as being a shorthand for [class~="demo"], or #demo as a shorthand for [id="demo"].

  [data-hover~=foo][data-hover~=bar] {}
would target a tag like this:

    <div data-hover="foo bar"></div>
But not a tag like this:

    <div data-hover="foobar"></div>
More info about attribute selectors: https://drafts.csswg.org/selectors-4/#attribute-representati...


I wasn’t aware of the tilde attribute selector. Still a lot more characters, though.

The classList api is still a lot more suited for this than dataset. None of the modifications done through the dataset api would reflect in the DOM and be readable by CSS unless you were to convert the list to a space separated string and explicitly set the attribute. classList handles all of this for you.


> None of the modifications done through the dataset api would reflect in the DOM and be readable by CSS unless you were to convert the list to a space separated string and explicitly set the attribute.

I'm really not sure what you mean by this. If you set the data attribute any of these ways, it can be targeted in CSS with [data-demo="example"]:

    el.dataset.demo = 'example'
    el.dataset['demo'] = 'example'
    el.setAttribute('demo', 'example')
CSS doesn't require a space separated anything. When you use an attribute selector in CSS it treats the entire value as a string, spaces included. But it's not classes versus attribute selectors, as class is an attribute, and therefore also something you can select with attribute selectors.

Also, think about the asymmetry between CSS and HTML when considering saving characters, one CSS selector targets ∞ tags, so I'd rather write slightly longer selector one time, than need to use a much longer 'namespaced' value on each element where I want the style to apply. That's leveraging what CSS does best!


I'm just saying if you want to target something on an element it needs to be set in an attribute and classList takes care of this.

I use classes strictly for styling. I change these styles by adding and removing class names and classList handles it very well without me needing to read the data attribute, make it an array, manipulate it, join it and update the attribute.


I feel like you're still thinking small in terms of attributes, and big in terms of values. Many many values all crammed into one attribute (class), but the reality is you can invent infinite (∞) data attributes. There's literally no need for you to format the values as a list of space-separated values…unless you want to. But if you don't want to, there's no need. Consider this, instead of targeting something with classes like this .active.demo, and setting it like this

    el.classList.add('active')
    el.classList.add('demo')
You would NOT need to do something like this to use data attributes, [data-example~=active][data-example~=demo] and to set it like this:

    if (!el.dataset.example.split(' ').includes('demo')) {
      el.dataset.example += ' demo'
    }
You could instead easily set two attributes and test for their presence, even if they don't have values (or you're not using them)

    el.dataset.active = el.dataset.demo = true
And then you can target that in CSS with [data-active][data-demo]. To remove them later is just as simple:

    el.dataset.active = false
And it's gone! Try to think BIG in terms of attributes, and small in terms of values. It's a lot nicer than trying to cram all of your values into just one attribute when you literally have infinite attributes available to work with!

Not only do you have infinite attributes to work with, but you can

Using classes as your only way to target styles, and ignoring the other aspects of how CSS selectors can target elements is like picking up a guitar and trying to play a song, but only plucking one string. You might be making it harder on yourself to get the job done, and the result isn't any better for the effort.

EDIT: Just for kicks, have you ever considered the flexibility of what data types you can set as an attribute value other than a space separated list of strings? Try this:

    // set JSON to attribute value
    document.documentElement.dataset.example = JSON.stringify({one: 1, two: 2})

    // get JSON from attribute value
    JSON.parse(document.documentElement.dataset.example)
You can even stick a bit of JSON there as the attribute value, which can be parse/stringified by JS, is _easy_ to add or remove properties from and work with on the JS side (not requiring helper methods like classList), and is _still_ targetable by CSS once set on an element :D The possibilities are endless, the apparent limitations a lot of people butt up against are self-imposed.


I'm sorry I'm just not seeing the value in it. I'm just seeing more complexity JS and CSS wise without solving any problems.


I'm a frontend developer of about 15 years as well and I think functional css makes a lot of sense. My biggest argument for it is not having to name every thing. You know how many times I've had to think of a name for a random container that exists simply to align some crap? Then if you need another wrapper or something for that for some reason? It eliminates the name game (whenever you want it to).


> My biggest argument for it is not having to name every thing.

This x 100. As a guy who is the only American on a team with a bunch of non-native speakers, taking away naming responsibility is a big win.


this sounds like me. I spend more time looking at a thesaurus than I do CSS articles


You can use `text-primary` or `text-secondary`. Sure it's less obvious looking at the markup what something looks like but it allows for theming.


Hopefully most are updating the property and not the attribute.


For those that are confused, updating the property would mean:

  this.input.value = 'password'; 
This would be fine. However updating the attribute (the way React recommends it with controlled components) would be something like:

  <input type="text" value={this.state.value} onChange={this.handleChange} />
This would be vulnerable to the the CSS keylogger.


That being said, you might be thinking about this incorrectly if you're doing this.

You can use a form and grab the values on submission.

    <form onSubmit={this.handleSubmission}>
      <input type="password" name="password" />
    </form>

    this.handleSubmission = event => {
      // access to event.target.password.value
    }


You still lose things like validation on blur and displaying real-time password strength.


It might be a fair workaround, but it sucks to regress to storing truth in the DOM.


I believe using `defaultValue` instead of `value` would be an appropriate remediation.


Do you mind expanding on this a little? Or linking to a documentation or something


I think he/she essentially means using an uncontrolled input instead of a controlled one.

https://reactjs.org/docs/uncontrolled-components.html#defaul...


Thanks!


It updates the attribute, you can see this pretty easily by going to the Instagram website. If you inspect the password field in the browser, when you type in a value you can see it reflected on the `value` attribute of the input element.


But that requires extra work, compared to simple JSX-based React code, doesn't it?


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: