由Astro群岛和老虎机造成的克服造型挫败感
#css #astro

使用Astro一段时间后,我意识到Astro的最大特色岛屿和老虎机既喜悦又沮丧。

大多数人已经知道乐趣是什么,所以我不会在本文中写关于他们的文章。我将专注于使我沮丧的原因以及如何解决这些挫败感。

首先,我们需要谈论Astro何时创建岛屿和老虎机。

当Astro创建岛屿和老虎机时

Astro将创建一个astro-island标签,以及stylescript标签,当您包含一个带有客户指令的组件时。

---
import Component from './components/Component.svelte'
---

<Component client:load />

如果组件(带有客户指令)包含一个slot,则Astro将创建一个astro-slot标签。该astro-slot将在astro-island中找到。

---
import Component from './components/Component.svelte'
---

<Component client:load>
  <div>Some Slotted Content</div>
</Component>

现在,如果您包括没有客户指令的组件,Astro将不会创建astro-islandastro-slot标签。

---
import Component from './components/Component.svelte'
---

<Component>
  <div>Some Slotted Content</div>
</Component>

天文岛和老虎机让什么令人沮丧

由于Astro仅在包含客户端指令时才创建这些标签,因此样式组件可能会变得不可预测,因为某些组件将具有客户指令,而其他组件则不会。

当DOM包含astro-islandastro-slots时,出现问题。那是因为这些标签会改变文档流,因此您不能假装它们不存在。

更具体地,我注意到当dom中出现astro-islandastro-slot时,我注意到了四个非常令人沮丧的事情。

  1. 直接后代选择器不再工作
  2. Lobotomized猫头鹰不再工作
  3. CSS网格定位不再起作用
  4. nth-child不再有效

我将依次谈论每个人,以及如何解决这些挫败感。

直接后代选择器不再工作

astro-islandastro-slot在DOM中,直接后代选择器不再工作。

这是有道理的,因为DOM已更改,因此直接后代选择器不再针对您要定位的元素。

想象您想拥有此HTML

<div class="Component">
  <div>Some Content</div>
</div>

但是Astro创建了此HTML,因为它具有插槽。

<div class="Component">
  <astro-slot>
    <div>Some Content</div>
  </astro-slot>
</div>

如果您编写了直接后代选择器,则选择器将不起作用。这是因为直接后代选择器现在针对astro-slot级的孩子,而不是您的目标。

/* No longer works */
.Component > div {
  /* Styles here */
}

修复它

用插槽修复直接后代选择器很简单 - 您要做的就是在选择器链中添加astro-slot

/* Works */
.Component > astro-slot > div {
  /* Styles here */
}

上面的代码片段假定您正在编写全局CSS。如果您使用的CSS范围为组件,则必须编写以下内容,因为我们正在处理插槽。

/* Scoped CSS*/
.Component :global(> astro-slot > div) {
  /* Styles here */
}

另一种选择是仅使用descend选择器而不是直接后代选择器如果HTML结构允许。

/* Works */
.Component div {
  /* Styles here */
}

让我们继续前进。

Lobotomized猫头鹰不再工作

Lobotomized Owl是一种使用兄弟姐妹通用选择器来设计事物的方式。 It was first coined by Heydon Pickering在2014年。

/* Lobotomized owl selector */
* + * {
  /* Your styles here */
}

可以使用Lobotomized Owl选择器来轻松造型儿童元素 - 必要

这是我通常用来在元素之间提供一些空间的示例。

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

不幸的是,这些样式在astro-islandastro-slot标签上无法使用,因为它们使用了koude19 property

修复它

带有display: contents的元素将忽略其样式,因此添加到这些元素中的任何样式都将被忽略。

解决此操作的简单方法是将样式添加到astro-islandastro-slot中的元素中。

这就是CSS的样子。

.Parent > * + *,
.Parent > * + :where(astro-island, astro-slot) > *:first-child {
  margin-top: 1rem;
}

CSS网格定位不再起作用

这个类似于Lobotomization One One,因为Astro Islands和插槽使用display: contents,没有样式对它们进行。

这些样式包括grid-columngrid-row。因此,您将无法使用grid-column更改矛盾的定位。

这是一个示例,我们将所有物品放在两列网格中。在此示例中,尝试在astro-island上使用set grid-columnastro-slots无法正常工作。

---
import Component from './Component.svelte'
---

<div class='Grid'>
  <Component client:load />
  <Component client:load />
  <Component client:load />
</div>

<style>
  .Grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 1em;
  }

  /* Tries to make all grid items span the full width */
  .Grid > * {
    grid-column: 1 / -1;
  }
</style>

有两种解决此问题的方法。

修复它

第一种方法是用提到的技术绕过astro-islandastro-slot e。

.grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1em;
}

/* Tries to make all grid items span the full width */
.grid > *,
.grid > :where(astro-island, astro-slot) > *:first-child {
  grid-column: 1 / -1;
}

第二种方法是将组件放在另一个元素中。

<div class="Grid">
  <div><Component client:load /></div>
  <div><Component client:load /></div>
  <div><Component client:load /></div>
</div>
.Grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1em;
}

.Grid > * {
  grid-column: 1 / -1;
}

nth-child不再按预期工作

当Astro将astro-island添加到DOM时,它们还将styleand script标记同时添加了script标签。

由于stylescript标签也被视为儿童元素,因此您不能依赖nth-child选择器来定位正确的元素。

使用上面的相同代码示例,假设我们有以下HTML。

<div class="Grid">
  <Component client:load></Component>
  <Component client:load></Component>
  <Component client:load></Component>
</div>

这会产生看起来像这样的dom。

  • 第一个元素是style tag
  • 第二个元素是script tag
  • 接下来的三个元素是astro-island标签

Astro仅在DOM中一次包含组件的stylescript标签。这就是为什么您仅看到一个style标签和一个script而不是3个style标签和3个script标签。

如果要使用nth-child获取第一个组件,则需要传递nth-child(3)而不是nth-child(1)。那是因为第一个组件现在是DOM树中的第三个元素。

/* Style the first component, but it's the third child */
.Grid > *:nth-child(3) > .Component {
  background-color: red;
}

是的,我知道这很困惑。

有两种方法可以解决这个令人困惑的问题

修复它

第一种方法是用另一个元素包裹组件。

然后,您可以使用nth-child使用后代选择器来样式。

<div class="Grid">
  <div><Component client:load /></div>
  <div><Component client:load /></div>
  <div><Component client:load /></div>
</div>
/* Tries to make all grid items span the full width */
.Grid > *:first-child .Component {
  background-color: red;
}

第二种方法是停止使用nth-child并改用nth-of-type

.Grid > astro-island:nth-of-type(1) > .Component {
  background-color: red;
}

更深的挫败感

如果您需要将组件传递到一个插槽中,尤其是两个组件(parent One和slot中的一个)都需要JavaScript功能。

---
import Component from './components/Component.svelte'
import Nested from './components/Nested.svelte'
---

<Component client:load>
  <Nested client:load />
</Component>

Astro将创建以下布局:

  1. 高层的astro-island
  2. astro-slot在第二级(因为Component通过插槽获取内容)
  3. astro-slot之后的另一个astro-island,因为Nested也需要具有JavaScript功能。

我不确定这种复杂性是否需要。

大多数时候,我只有一层astro-island和一层astro-slot。因此,这应该比其他任何事物都重要。

包起来

我刚刚与您分享了Astro何时以及如何创建astro-islandastro-slot

我还与您分享了如何克服dom中存在astro-islandastro-slot元素时发生的样式挫败感。

这样,您现在应该能够有效地使用Astro而不会遇到进一步的样式问题。

希望您在编码旅程中发现这很有用。

如果您希望收到有关Astro,Svelte和其他Web开发主题的更多深入的文章,请随时在下面注册我的新闻通讯。

今天就这样。感谢您的阅读!

顺便说一句,本文最初写在我的blog上。如果您想在发布时直接将这些文章交付给您的电子邮件,请随时访问! ð。