使用Astro一段时间后,我意识到Astro的最大特色岛屿和老虎机既喜悦又沮丧。
大多数人已经知道乐趣是什么,所以我不会在本文中写关于他们的文章。我将专注于使我沮丧的原因以及如何解决这些挫败感。
首先,我们需要谈论Astro何时创建岛屿和老虎机。
当Astro创建岛屿和老虎机时
Astro将创建一个astro-island
标签,以及style
和script
标签,当您包含一个带有客户指令的组件时。
---
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-island
和astro-slot
标签。
---
import Component from './components/Component.svelte'
---
<Component>
<div>Some Slotted Content</div>
</Component>
天文岛和老虎机让什么令人沮丧
由于Astro仅在包含客户端指令时才创建这些标签,因此样式组件可能会变得不可预测,因为某些组件将具有客户指令,而其他组件则不会。
当DOM包含astro-island
和astro-slots
时,出现问题。那是因为这些标签会改变文档流,因此您不能假装它们不存在。
更具体地,我注意到当dom中出现astro-island
和astro-slot
时,我注意到了四个非常令人沮丧的事情。
- 直接后代选择器不再工作
- Lobotomized猫头鹰不再工作
- CSS网格定位不再起作用
- nth-child不再有效
我将依次谈论每个人,以及如何解决这些挫败感。
直接后代选择器不再工作
当astro-island
和astro-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-island
和astro-slot
标签上无法使用,因为它们使用了koude19 property。
修复它
带有display: contents
的元素将忽略其样式,因此添加到这些元素中的任何样式都将被忽略。
解决此操作的简单方法是将样式添加到astro-island
或astro-slot
中的元素中。
这就是CSS的样子。
.Parent > * + *,
.Parent > * + :where(astro-island, astro-slot) > *:first-child {
margin-top: 1rem;
}
CSS网格定位不再起作用
这个类似于Lobotomization One One,因为Astro Islands和插槽使用display: contents
,没有样式对它们进行。
这些样式包括grid-column
,grid-row
。因此,您将无法使用grid-column
更改矛盾的定位。
这是一个示例,我们将所有物品放在两列网格中。在此示例中,尝试在astro-island
上使用set grid-column
和astro-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-island
和astro-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时,它们还将style
and script
标记同时添加了script
标签。
由于style
和script
标签也被视为儿童元素,因此您不能依赖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中一次包含组件的style
和script
标签。这就是为什么您仅看到一个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将创建以下布局:
-
高层的
astro-island
-
astro-slot
在第二级(因为Component
通过插槽获取内容) -
astro-slot
之后的另一个astro-island
,因为Nested
也需要具有JavaScript功能。
我不确定这种复杂性是否需要。
大多数时候,我只有一层astro-island
和一层astro-slot
。因此,这应该比其他任何事物都重要。
包起来
我刚刚与您分享了Astro何时以及如何创建astro-island
和astro-slot
。
我还与您分享了如何克服dom中存在astro-island
和astro-slot
元素时发生的样式挫败感。
这样,您现在应该能够有效地使用Astro而不会遇到进一步的样式问题。
希望您在编码旅程中发现这很有用。
如果您希望收到有关Astro,Svelte和其他Web开发主题的更多深入的文章,请随时在下面注册我的新闻通讯。
今天就这样。感谢您的阅读!
顺便说一句,本文最初写在我的blog上。如果您想在发布时直接将这些文章交付给您的电子邮件,请随时访问! ð。