Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rules on universal selector (*) and combinors prevent using the 'lobotomised owl' selector (:scope > * + *) #508

Open
JoshTumath opened this issue Sep 28, 2020 · 2 comments

Comments

@JoshTumath
Copy link

JoshTumath commented Sep 28, 2020

I love the concept of CSS Blocks and would love to use it in my team's design system. However, it expressly forbids the use of a selector like :scope > * + * (known to some people as the lobotomised owl selector). I want to present our use-case to you and see what you think! Maybe this is a convincing argument for CSS Blocks to support the owl selector, or maybe there's an equivalent alternative way of doing the same thing in CSS Blocks that solves the same problem.

Use case: layout components

In a design system, you want components to be self contained and not have to worry about how they're laid out. We have a rule in our design system called 'No outer margins'. It should be possible to use a component anywhere without having to worry about where it will be used. If the component has a margin on the outside, it may have a gap around it where you haven't intended it.

So how do you set gaps and margins between components? In our design system, that's a the parent component's responsibility to compose them together. We call the components that have this responsibility 'layout components'.

For example, a layout component called Grid would use CSS Grid to lay out its children. And the gap property would set the gap between components. I wouldn't need to go outside of the scope of the Grid component to set the gap between child components because of the way CSS Grid works; that can be done from the parent.

/* Grid */
:scope {
  display: grid;
  gap: 1rem;
}

However, if I don't need to use a grid layout - if I just want a stack of paragraphs and images in an article to be laid out one-below-the-other - I just need the default CSS flow layout. So I need to use a margin to set a space/gap between components. That's where the owl selector comes in. I can create a layout component called Stack and it will set a gap between its children; I don't need to worry about what components those children are. (The Book 'Every Layout' makes a great case for the owl selector when explaining the Stack layout.)

<Stack>
  <h1>CSS is awesome</h1>
  <p>Foo</p>
  <p>Foo</p>
  <p>Foo</p>
</Stack>
/* Stack */
:scope {
  display: block;
}

:scope > * + * {
  margin-top: 1rem;
}

It's a similar problem if you're using CSS Flex to create a layout, and you need to add the flex property to the children to set varying flex amounts.

@lougreenwood
Copy link

Would it be possible to use :scope > *:not(:last-child) instead?

@JoshTumath
Copy link
Author

JoshTumath commented Sep 29, 2020

Would it be possible to use :scope > *:not(:last-child) instead?

Yeah that would do the same thing. However, I would have thought that be against the rules of the system as well, since the universal selector is forbidden. Wouldn't the :not pseudo-class have to be associated with a particular class (:scope > .foo:not(:last-child))?

With a layout component, you don't know what the classes of the child elements are going to be. 🙂

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants