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

Lobotomized owl CSS selector broken #3104

Closed
Munter opened this issue Jun 25, 2019 · 6 comments
Closed

Lobotomized owl CSS selector broken #3104

Munter opened this issue Jun 25, 2019 · 6 comments
Labels

Comments

@Munter
Copy link

@Munter Munter commented Jun 25, 2019

I like to use a pattern of a CSS flex-box with whildren evenly spaced using the lobotomized owl selector.

My CSS looks like this:

  .user-section {
    display: flex;
  }

  .user-section > * + * {
    margin-left: 4px;
  }

Svelte compiles it into this:

.user-section.svelte-1aasoha {
  display: flex
}

.user-section>*+.svelte-1aasoha {
  margin-left: 4px
}

The right eye of the owl is replaced with the unique Svelte-generated selector id for the flexbox. I expected the unique id to be appended to the flexbox selector before the > part of the selector.

Is the id just naively appended to the end of the selector? Maybe a whitespace collapse is set to happen too early when handling this selector.

Svelte version: 3.5.3

@marceloadsj
Copy link

@marceloadsj marceloadsj commented Jun 26, 2019

Maybe you will need to use the :global() modifier:
https://svelte.dev/repl/62df05ad1dd8451caa106918b210a5f7?version=3.6.1

<style>
  .user-section {
    display: flex;
  }

  .user-section > :global(* + *) {
    margin-left: 4px;
  }
</style>
@marceloadsj
Copy link

@marceloadsj marceloadsj commented Jun 26, 2019

Following the way the css selectors works, something like:

1-
This is a single selector: div

  • If we use a single selector, like * or div, Svelte will match the tags in that component, then it will inject the hash class and replace the css selector.

2-
This is an adjacent sibling selector: .user-section + *
That is equal to 2 single selectors combined: .user-section + *

  • in this case, svelte will read the entire selector and, if some path match a tag, it will do the same process as the example 1, replacing that part with the hash.

Each +, >, ~ "breaks" the selector in single parts. Svelte match the entire selector, but can replace each part of it with the class hash.

So, using the :global() modifier, you let svelte know you want that selector to keep on the code as it is!

And just one more thing to keep documented, lol. The class selectors, like .user-section are never replaced by svelte, it just add it's class hash on it!

@Conduitry
Copy link
Member

@Conduitry Conduitry commented Jan 20, 2020

It does indeed look like the issue here is that ~ and + combinators are not handled properly. Consider something like:

App.svelte

<script>
	import Foo from './Foo.svelte';
</script>

<Foo/>
<div>
	bar
</div>

<style>
	div + div {
		color: red;
	}
</style>

Foo.svelte

<div>
	foo
</div>

The styles shouldn't match anything, but they do. The <div> in the parent component gets a scoping class, and the selector in the styles changes to div+div.svelte-xyz.

In general, it seems like these combinators are getting handled by ignoring everything but the last part when seeing which parts of the document they might match, and then it's also only this last part of the selector that gets scoped.

@Conduitry
Copy link
Member

@Conduitry Conduitry commented Jan 20, 2020

There's a rather telling comment here which I don't remember really absorbing before. Only WhiteSpace and > combinators have handling currently.

@Conduitry
Copy link
Member

@Conduitry Conduitry commented Jan 20, 2020

I was just thinking about this more, and there seem to be a lot more things to worry about with sibling selectors than with the other ones. For example:

{#each foo as bar}
	<div class='a'>...</div>
	<div class='b'>...</div>
{/each}

then .b + .a is a valid selector, because the loop will wrap around. In general, there seems to be a large number of cases to cover when deciding whether two elements can be (adjacent or non-adjacent) siblings when {#if}s/{#each}s/{:else}s/{#await}s become involved.

@Conduitry
Copy link
Member

@Conduitry Conduitry commented Sep 24, 2020

~ / + should now be getting scoped properly in v3.27.0.

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

Successfully merging a pull request may close this issue.

3 participants
You can’t perform that action at this time.