Search code examples
csstailwind-css

Recreating CSS "not" using Tailwind


I'm having some difficult recreating using Tailwind some CSS I found online.

The full implementation is demoed in this code snippet: https://codepen.io/kkellydesign/pen/WNKBdqL

HTML:

<div>
  <div>
    <div></div>  
  </div>
</div>

CSS:

div{max-width: 300px;max-height: 200px; background: red; padding: 40px;}
div div {background: purple}
div div div { background: pink}

div:not(:has(div:hover)):hover {
outline: 5px solid black;
}

The specific part I'm having trouble recreating using Tailwind is

div:not(:has(div:hover)):hover

Any help is greatly appreciated!


Solution

  • Arbitrary variant

    You could transpose the selector to an arbitrary variant. Pick a "sensible" point of reference for & to transpose. You could pick the first <div>:

    div{max-width: 300px;max-height: 200px; background: red; padding: 40px;}
    div div {background: purple}
    div div div { background: pink}
    <script src="https://cdn.tailwindcss.com/3.4.16"></script>
    
    <div class="[&:not(:has(div:hover)):hover]:outline [&:not(:has(div:hover)):hover]:outline-[5px] [&:not(:has(div:hover)):hover]:outline-black">
      <div class="[&:not(:has(div:hover)):hover]:outline [&:not(:has(div:hover)):hover]:outline-[5px] [&:not(:has(div:hover)):hover]:outline-black">
        <div class="[&:not(:has(div:hover)):hover]:outline [&:not(:has(div:hover)):hover]:outline-[5px] [&:not(:has(div:hover)):hover]:outline-black"></div>  
      </div>
    </div>

    Or have a container if you don't want to repeat the set of classes on every <div>:

    div{max-width: 300px;max-height: 200px; background: red; padding: 40px;}
    div div {background: purple}
    div div div { background: pink}
    <script src="https://cdn.tailwindcss.com/3.4.16"></script>
    
    <section class="[&_div:not(:has(div:hover)):hover]:outline [&_div:not(:has(div:hover)):hover]:outline-[5px] [&_div:not(:has(div:hover)):hover]:outline-black">
      <div>
        <div>
          <div></div>
        </div>
      </div>
    </section>

    Built-ins

    To feel more like "Tailwind", you could also try using the built-in variants where they exist. We can break it down into two parts, the :hover, and the :not(…). We can't break :not(…) down since that will need to be an arbitrary variant since :not() does not exist as a built-in variant:

    div{max-width: 300px;max-height: 200px; background: red; padding: 40px;}
    div div {background: purple}
    div div div { background: pink}
    <script src="https://cdn.tailwindcss.com/3.4.16"></script>
    
    <div class="hover:[&:not(:has(div:hover))]:outline hover:[&:not(:has(div:hover))]:outline-[5px] hover:[&:not(:has(div:hover))]:outline-black">
      <div class="hover:[&:not(:has(div:hover))]:outline hover:[&:not(:has(div:hover))]:outline-[5px] hover:[&:not(:has(div:hover))]:outline-black">
        <div class="hover:[&:not(:has(div:hover))]:outline hover:[&:not(:has(div:hover))]:outline-[5px] hover:[&:not(:has(div:hover))]:outline-black"></div>
      </div>
    </div>

    Plugin

    You can also abstract any of the arbitrary variants used previously to a custom variant using a Tailwind plugin:

    tailwind.config = {
      plugins: [
        tailwind.plugin(({ addVariant }) => {
          addVariant('foo', '&:not(:has(div:hover)):hover');
          addVariant('bar', '& div:not(:has(div:hover)):hover');
          addVariant('baz', '&:not(:has(div:hover))');
        }),
      ],
    };
    div{max-width: 300px;max-height: 200px; background: red; padding: 40px;}
    div div {background: purple}
    div div div { background: pink}
    <script src="https://cdn.tailwindcss.com/3.4.16"></script>
    
    <div class="foo:outline foo:outline-[5px] foo:outline-black">
      <div class="foo:outline foo:outline-[5px] foo:outline-black">
        <div class="foo:outline foo:outline-[5px] foo:outline-black"></div>  
      </div>
    </div>
    
    <section class="bar:outline bar:outline-[5px] bar:outline-black">
      <div>
        <div>
          <div></div>
        </div>
      </div>
    </section>
    
    <div class="hover:baz:outline hover:baz:outline-[5px] hover:baz:outline-black">
      <div class="hover:baz:outline hover:baz:outline-[5px] hover:baz:outline-black">
        <div class="hover:baz:outline hover:baz:outline-[5px] hover:baz:outline-black"></div>
      </div>
    </div>