Don't accommodate hidden elements in space/divide #13459
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This PR changes the implementation of the
space-*
anddivide-*
utilities to use a different selector, and apply the "between" styling to the first/left element instead of the last/right element:This is a small breaking change, specifically when the very last child of an element has the
hidden
attribute:Prior to this PR, the "Three" element would have no space below it, but with this new implementation it does. I suspect this change will impact almost nobody though, because in all of the real-world scenarios I've explored, hidden elements are never the very last element. They are almost always the very first element, or first few elements, and in those situations this new implementation has the same behavior as the old implementation.
Motivation
The "between" styling that we do with
space-*
anddivide-*
is most commonly achieved in CSS with the "lobotomized owl selector", like this:Our implementation in Tailwind though has always used selectors that look like this:
Pretty much the only reason we did this was so that you could use these utilities with
x-for
in Alpine.jsAlpine leaves that
<template>
tag in the DOM, which means the first<li>
is actually the second child of the<ul>
, and receives the "between" styling even when it shouldn't:https://play.tailwindcss.com/7q6MiKZnRg
By using the implementation we've used up until now, Alpine users could throw the
hidden
attribute on their<template>
element and now the "between" styling would only show up where it's supposed to:https://play.tailwindcss.com/p6ZGpSw1zt
The problem is on pages with a lot of DOM nodes, the selector we use is fucking slow 😄
https://twitter.com/cramforce/status/1774847095171862943
It's not just "technically slow but you can't actually tell because it's still fast" either — if you have a really big list or table or something it's very, very noticeable:
#13445
The new implementation introduced in this PR is almost 2000x faster, getting things back down to "feels as fast as any other normal selector" speeds.
One nice benefit of the new implementation is that you don't need to use the
hidden
attribute ontemplate
tags anymore — the "between" styling just works as expected without it because thetemplate
tag is receiving amargin-bottom
for example but the entire element is hidden so that margin isn't actually rendered in the browser anyways.