mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 05:41:12 +00:00
Bug 1850974 - Make :is(:host) work. r=zrhoffman
This should work per spec, see https://github.com/w3c/csswg-drafts/issues/9509. Tweak a bit the selector flags set up so that checking for :host selectors during CascadeData rebuilds is cheap. Differential Revision: https://phabricator.services.mozilla.com/D191570
This commit is contained in:
parent
2775ca27cd
commit
f4542a93c1
@ -176,10 +176,12 @@ bitflags! {
|
||||
const HAS_SLOTTED = 1 << 1;
|
||||
const HAS_PART = 1 << 2;
|
||||
const HAS_PARENT = 1 << 3;
|
||||
const HAS_NON_FEATURELESS_COMPONENT = 1 << 4;
|
||||
const HAS_HOST = 1 << 5;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, ToShmem)]
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, ToShmem)]
|
||||
pub struct SpecificityAndFlags {
|
||||
/// There are two free bits here, since we use ten bits for each specificity
|
||||
/// kind (id, class, element).
|
||||
@ -188,33 +190,6 @@ pub struct SpecificityAndFlags {
|
||||
pub(crate) flags: SelectorFlags,
|
||||
}
|
||||
|
||||
impl SpecificityAndFlags {
|
||||
#[inline]
|
||||
pub fn specificity(&self) -> u32 {
|
||||
self.specificity
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn has_pseudo_element(&self) -> bool {
|
||||
self.flags.intersects(SelectorFlags::HAS_PSEUDO)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn has_parent_selector(&self) -> bool {
|
||||
self.flags.intersects(SelectorFlags::HAS_PARENT)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_slotted(&self) -> bool {
|
||||
self.flags.intersects(SelectorFlags::HAS_SLOTTED)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_part(&self) -> bool {
|
||||
self.flags.intersects(SelectorFlags::HAS_PART)
|
||||
}
|
||||
}
|
||||
|
||||
const MAX_10BIT: u32 = (1u32 << 10) - 1;
|
||||
|
||||
#[derive(Add, AddAssign, Clone, Copy, Default, Eq, Ord, PartialEq, PartialOrd)]
|
||||
@ -276,9 +251,12 @@ where
|
||||
flags.insert(SelectorFlags::HAS_PSEUDO);
|
||||
specificity.element_selectors += 1
|
||||
},
|
||||
Component::LocalName(..) => specificity.element_selectors += 1,
|
||||
Component::LocalName(..) => {
|
||||
flags.insert(SelectorFlags::HAS_NON_FEATURELESS_COMPONENT);
|
||||
specificity.element_selectors += 1
|
||||
},
|
||||
Component::Slotted(ref selector) => {
|
||||
flags.insert(SelectorFlags::HAS_SLOTTED);
|
||||
flags.insert(SelectorFlags::HAS_SLOTTED | SelectorFlags::HAS_NON_FEATURELESS_COMPONENT);
|
||||
specificity.element_selectors += 1;
|
||||
// Note that due to the way ::slotted works we only compete with
|
||||
// other ::slotted rules, so the above rule doesn't really
|
||||
@ -287,21 +265,19 @@ where
|
||||
//
|
||||
// See: https://github.com/w3c/csswg-drafts/issues/1915
|
||||
*specificity += Specificity::from(selector.specificity());
|
||||
if selector.has_parent_selector() {
|
||||
flags.insert(SelectorFlags::HAS_PARENT);
|
||||
}
|
||||
flags.insert(selector.flags());
|
||||
},
|
||||
Component::Host(ref selector) => {
|
||||
flags.insert(SelectorFlags::HAS_HOST);
|
||||
specificity.class_like_selectors += 1;
|
||||
if let Some(ref selector) = *selector {
|
||||
// See: https://github.com/w3c/csswg-drafts/issues/1915
|
||||
*specificity += Specificity::from(selector.specificity());
|
||||
if selector.has_parent_selector() {
|
||||
flags.insert(SelectorFlags::HAS_PARENT);
|
||||
}
|
||||
flags.insert(selector.flags() - SelectorFlags::HAS_NON_FEATURELESS_COMPONENT);
|
||||
}
|
||||
},
|
||||
Component::ID(..) => {
|
||||
flags.insert(SelectorFlags::HAS_NON_FEATURELESS_COMPONENT);
|
||||
specificity.id_selectors += 1;
|
||||
},
|
||||
Component::Class(..) |
|
||||
@ -313,6 +289,7 @@ where
|
||||
Component::Scope |
|
||||
Component::Nth(..) |
|
||||
Component::NonTSPseudoClass(..) => {
|
||||
flags.insert(SelectorFlags::HAS_NON_FEATURELESS_COMPONENT);
|
||||
specificity.class_like_selectors += 1;
|
||||
},
|
||||
Component::NthOf(ref nth_of_data) => {
|
||||
@ -325,7 +302,7 @@ where
|
||||
specificity.class_like_selectors += 1;
|
||||
let sf = selector_list_specificity_and_flags(nth_of_data.selectors().iter());
|
||||
*specificity += Specificity::from(sf.specificity);
|
||||
flags.insert(sf.flags);
|
||||
flags.insert(sf.flags | SelectorFlags::HAS_NON_FEATURELESS_COMPONENT);
|
||||
},
|
||||
// https://drafts.csswg.org/selectors/#specificity-rules:
|
||||
//
|
||||
@ -344,7 +321,7 @@ where
|
||||
Component::Has(ref relative_selectors) => {
|
||||
let sf = relative_selector_list_specificity_and_flags(relative_selectors);
|
||||
*specificity += Specificity::from(sf.specificity);
|
||||
flags.insert(sf.flags);
|
||||
flags.insert(sf.flags | SelectorFlags::HAS_NON_FEATURELESS_COMPONENT);
|
||||
},
|
||||
Component::ExplicitUniversalType |
|
||||
Component::ExplicitAnyNamespace |
|
||||
@ -354,6 +331,7 @@ where
|
||||
Component::RelativeSelectorAnchor |
|
||||
Component::Invalid(..) => {
|
||||
// Does not affect specificity
|
||||
flags.insert(SelectorFlags::HAS_NON_FEATURELESS_COMPONENT);
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -377,9 +355,7 @@ pub(crate) fn selector_list_specificity_and_flags<'a, Impl: SelectorImpl>(
|
||||
let mut flags = SelectorFlags::empty();
|
||||
for selector in itr {
|
||||
specificity = std::cmp::max(specificity, selector.specificity());
|
||||
if selector.has_parent_selector() {
|
||||
flags.insert(SelectorFlags::HAS_PARENT);
|
||||
}
|
||||
flags.insert(selector.flags());
|
||||
}
|
||||
SpecificityAndFlags { specificity, flags }
|
||||
}
|
||||
|
@ -735,32 +735,32 @@ impl<Impl: SelectorImpl> Selector<Impl> {
|
||||
|
||||
#[inline]
|
||||
pub fn specificity(&self) -> u32 {
|
||||
self.0.header.specificity()
|
||||
self.0.header.specificity
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn flags(&self) -> SelectorFlags {
|
||||
pub(crate) fn flags(&self) -> SelectorFlags {
|
||||
self.0.header.flags
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn has_pseudo_element(&self) -> bool {
|
||||
self.0.header.has_pseudo_element()
|
||||
self.flags().intersects(SelectorFlags::HAS_PSEUDO)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn has_parent_selector(&self) -> bool {
|
||||
self.0.header.has_parent_selector()
|
||||
self.flags().intersects(SelectorFlags::HAS_PARENT)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_slotted(&self) -> bool {
|
||||
self.0.header.is_slotted()
|
||||
self.flags().intersects(SelectorFlags::HAS_SLOTTED)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_part(&self) -> bool {
|
||||
self.0.header.is_part()
|
||||
self.flags().intersects(SelectorFlags::HAS_PART)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -855,27 +855,12 @@ impl<Impl: SelectorImpl> Selector<Impl> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether this selector is a featureless :host selector, with no
|
||||
/// combinators to the left, and optionally has a pseudo-element to the
|
||||
/// right.
|
||||
/// Whether this selector is a featureless :host selector, with no combinators to the left, and
|
||||
/// optionally has a pseudo-element to the right.
|
||||
#[inline]
|
||||
pub fn is_featureless_host_selector_or_pseudo_element(&self) -> bool {
|
||||
let mut iter = self.iter();
|
||||
if !self.has_pseudo_element() {
|
||||
return iter.is_featureless_host_selector();
|
||||
}
|
||||
|
||||
// Skip the pseudo-element.
|
||||
for _ in &mut iter {}
|
||||
|
||||
match iter.next_sequence() {
|
||||
None => return false,
|
||||
Some(combinator) => {
|
||||
debug_assert_eq!(combinator, Combinator::PseudoElement);
|
||||
},
|
||||
}
|
||||
|
||||
iter.is_featureless_host_selector()
|
||||
let flags = self.flags();
|
||||
flags.intersects(SelectorFlags::HAS_HOST) && !flags.intersects(SelectorFlags::HAS_NON_FEATURELESS_COMPONENT)
|
||||
}
|
||||
|
||||
/// Returns an iterator over this selector in matching order (right-to-left),
|
||||
@ -955,27 +940,22 @@ impl<Impl: SelectorImpl> Selector<Impl> {
|
||||
}
|
||||
|
||||
pub fn replace_parent_selector(&self, parent: &SelectorList<Impl>) -> Self {
|
||||
// FIXME(emilio): Shouldn't allow replacing if parent has a pseudo-element selector
|
||||
// or what not.
|
||||
let flags = self.flags() - SelectorFlags::HAS_PARENT;
|
||||
let mut specificity = Specificity::from(self.specificity());
|
||||
let parent_specificity =
|
||||
Specificity::from(selector_list_specificity_and_flags(parent.slice().iter()).specificity());
|
||||
let parent_specificity_and_flags = selector_list_specificity_and_flags(parent.slice().iter());
|
||||
|
||||
// The specificity at this point will be wrong, we replace it by the correct one after the
|
||||
// fact.
|
||||
let specificity_and_flags = SpecificityAndFlags {
|
||||
specificity: self.specificity(),
|
||||
flags,
|
||||
};
|
||||
let mut specificity = Specificity::from(self.specificity());
|
||||
let mut flags = self.flags() - SelectorFlags::HAS_PARENT;
|
||||
|
||||
fn replace_parent_on_selector_list<Impl: SelectorImpl>(
|
||||
orig: &[Selector<Impl>],
|
||||
parent: &SelectorList<Impl>,
|
||||
specificity: &mut Specificity,
|
||||
with_specificity: bool,
|
||||
flags: &mut SelectorFlags,
|
||||
propagate_specificity: bool,
|
||||
flags_to_propagate: SelectorFlags,
|
||||
) -> Option<SelectorList<Impl>> {
|
||||
let mut any = false;
|
||||
if !orig.iter().any(|s| s.has_parent_selector()) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let result = SelectorList::from_iter(
|
||||
orig
|
||||
@ -984,23 +964,19 @@ impl<Impl: SelectorImpl> Selector<Impl> {
|
||||
if !s.has_parent_selector() {
|
||||
return s.clone();
|
||||
}
|
||||
any = true;
|
||||
s.replace_parent_selector(parent)
|
||||
})
|
||||
);
|
||||
|
||||
if !any {
|
||||
return None;
|
||||
let result_specificity_and_flags =
|
||||
selector_list_specificity_and_flags(result.slice().iter());
|
||||
if propagate_specificity {
|
||||
*specificity += Specificity::from(
|
||||
result_specificity_and_flags.specificity -
|
||||
selector_list_specificity_and_flags(orig.iter()).specificity,
|
||||
);
|
||||
}
|
||||
|
||||
if !with_specificity {
|
||||
return Some(result);
|
||||
}
|
||||
|
||||
*specificity += Specificity::from(
|
||||
selector_list_specificity_and_flags(result.slice().iter()).specificity -
|
||||
selector_list_specificity_and_flags(orig.iter()).specificity,
|
||||
);
|
||||
flags.insert(result_specificity_and_flags.flags.intersection(flags_to_propagate));
|
||||
Some(result)
|
||||
}
|
||||
|
||||
@ -1008,6 +984,8 @@ impl<Impl: SelectorImpl> Selector<Impl> {
|
||||
orig: &[RelativeSelector<Impl>],
|
||||
parent: &SelectorList<Impl>,
|
||||
specificity: &mut Specificity,
|
||||
flags: &mut SelectorFlags,
|
||||
flags_to_propagate: SelectorFlags,
|
||||
) -> Vec<RelativeSelector<Impl>> {
|
||||
let mut any = false;
|
||||
|
||||
@ -1029,8 +1007,10 @@ impl<Impl: SelectorImpl> Selector<Impl> {
|
||||
return result;
|
||||
}
|
||||
|
||||
let result_specificity_and_flags = relative_selector_list_specificity_and_flags(&result);
|
||||
flags.insert(result_specificity_and_flags.flags.intersection(flags_to_propagate));
|
||||
*specificity += Specificity::from(
|
||||
relative_selector_list_specificity_and_flags(&result).specificity -
|
||||
result_specificity_and_flags.specificity -
|
||||
relative_selector_list_specificity_and_flags(orig).specificity,
|
||||
);
|
||||
result
|
||||
@ -1040,12 +1020,15 @@ impl<Impl: SelectorImpl> Selector<Impl> {
|
||||
orig: &Selector<Impl>,
|
||||
parent: &SelectorList<Impl>,
|
||||
specificity: &mut Specificity,
|
||||
flags: &mut SelectorFlags,
|
||||
flags_to_propagate: SelectorFlags,
|
||||
) -> Selector<Impl> {
|
||||
if !orig.has_parent_selector() {
|
||||
return orig.clone();
|
||||
}
|
||||
let new_selector = orig.replace_parent_selector(parent);
|
||||
*specificity += Specificity::from(new_selector.specificity() - orig.specificity());
|
||||
flags.insert(new_selector.flags().intersection(flags_to_propagate));
|
||||
new_selector
|
||||
}
|
||||
|
||||
@ -1053,7 +1036,8 @@ impl<Impl: SelectorImpl> Selector<Impl> {
|
||||
// Implicit `&` plus descendant combinator.
|
||||
let iter = self.iter_raw_match_order();
|
||||
let len = iter.len() + 2;
|
||||
specificity += parent_specificity;
|
||||
specificity += Specificity::from(parent_specificity_and_flags.specificity);
|
||||
flags.insert(parent_specificity_and_flags.flags);
|
||||
let iter = iter
|
||||
.cloned()
|
||||
.chain(std::iter::once(Component::Combinator(
|
||||
@ -1062,7 +1046,7 @@ impl<Impl: SelectorImpl> Selector<Impl> {
|
||||
.chain(std::iter::once(Component::Is(
|
||||
parent.clone()
|
||||
)));
|
||||
UniqueArc::from_header_and_iter_with_size(specificity_and_flags, iter, len)
|
||||
UniqueArc::from_header_and_iter_with_size(Default::default(), iter, len)
|
||||
} else {
|
||||
let iter = self.iter_raw_match_order().map(|component| {
|
||||
use self::Component::*;
|
||||
@ -1090,7 +1074,8 @@ impl<Impl: SelectorImpl> Selector<Impl> {
|
||||
Invalid(..) |
|
||||
RelativeSelectorAnchor => component.clone(),
|
||||
ParentSelector => {
|
||||
specificity += parent_specificity;
|
||||
specificity += Specificity::from(parent_specificity_and_flags.specificity);
|
||||
flags.insert(parent_specificity_and_flags.flags);
|
||||
Is(parent.clone())
|
||||
},
|
||||
Negation(ref selectors) => {
|
||||
@ -1098,7 +1083,9 @@ impl<Impl: SelectorImpl> Selector<Impl> {
|
||||
selectors.slice(),
|
||||
parent,
|
||||
&mut specificity,
|
||||
/* with_specificity = */ true,
|
||||
&mut flags,
|
||||
/* propagate_specificity = */ true,
|
||||
SelectorFlags::all(),
|
||||
).unwrap_or_else(|| selectors.clone()))
|
||||
},
|
||||
Is(ref selectors) => {
|
||||
@ -1106,7 +1093,9 @@ impl<Impl: SelectorImpl> Selector<Impl> {
|
||||
selectors.slice(),
|
||||
parent,
|
||||
&mut specificity,
|
||||
/* with_specificity = */ true,
|
||||
&mut flags,
|
||||
/* propagate_specificity = */ true,
|
||||
SelectorFlags::all(),
|
||||
).unwrap_or_else(|| selectors.clone()))
|
||||
},
|
||||
Where(ref selectors) => {
|
||||
@ -1114,13 +1103,17 @@ impl<Impl: SelectorImpl> Selector<Impl> {
|
||||
selectors.slice(),
|
||||
parent,
|
||||
&mut specificity,
|
||||
/* with_specificity = */ false,
|
||||
&mut flags,
|
||||
/* propagate_specificity = */ false,
|
||||
SelectorFlags::all(),
|
||||
).unwrap_or_else(|| selectors.clone()))
|
||||
},
|
||||
Has(ref selectors) => Has(replace_parent_on_relative_selector_list(
|
||||
selectors,
|
||||
parent,
|
||||
&mut specificity,
|
||||
&mut flags,
|
||||
SelectorFlags::all(),
|
||||
)
|
||||
.into_boxed_slice()),
|
||||
|
||||
@ -1128,13 +1121,17 @@ impl<Impl: SelectorImpl> Selector<Impl> {
|
||||
selector,
|
||||
parent,
|
||||
&mut specificity,
|
||||
&mut flags,
|
||||
SelectorFlags::all() - SelectorFlags::HAS_NON_FEATURELESS_COMPONENT,
|
||||
))),
|
||||
NthOf(ref data) => {
|
||||
let selectors = replace_parent_on_selector_list(
|
||||
data.selectors(),
|
||||
parent,
|
||||
&mut specificity,
|
||||
/* with_specificity = */ true,
|
||||
&mut flags,
|
||||
/* propagate_specificity = */ true,
|
||||
SelectorFlags::all(),
|
||||
);
|
||||
NthOf(match selectors {
|
||||
Some(s) => NthOfSelectorData::new(
|
||||
@ -1148,12 +1145,17 @@ impl<Impl: SelectorImpl> Selector<Impl> {
|
||||
selector,
|
||||
parent,
|
||||
&mut specificity,
|
||||
&mut flags,
|
||||
SelectorFlags::all(),
|
||||
)),
|
||||
}
|
||||
});
|
||||
UniqueArc::from_header_and_iter(specificity_and_flags, iter)
|
||||
UniqueArc::from_header_and_iter(Default::default(), iter)
|
||||
};
|
||||
*items.header_mut() = SpecificityAndFlags {
|
||||
specificity: specificity.into(),
|
||||
flags,
|
||||
};
|
||||
items.header_mut().specificity = specificity.into();
|
||||
Selector(items.shareable())
|
||||
}
|
||||
|
||||
@ -1291,7 +1293,7 @@ impl<'a, Impl: 'a + SelectorImpl> SelectorIter<'a, Impl> {
|
||||
#[inline]
|
||||
pub(crate) fn is_featureless_host_selector(&mut self) -> bool {
|
||||
self.selector_length() > 0 &&
|
||||
self.all(|component| component.is_host()) &&
|
||||
self.all(|component| component.matches_featureless_host()) &&
|
||||
self.next_sequence().is_none()
|
||||
}
|
||||
|
||||
@ -1957,6 +1959,22 @@ impl<Impl: SelectorImpl> Component<Impl> {
|
||||
matches!(*self, Component::Host(..))
|
||||
}
|
||||
|
||||
/// Returns true if this is a :host() selector.
|
||||
#[inline]
|
||||
pub fn matches_featureless_host(&self) -> bool {
|
||||
match *self {
|
||||
Component::Host(..) => true,
|
||||
Component::Where(ref l) |
|
||||
Component::Is(ref l) => {
|
||||
// TODO(emilio): For now we use .all() rather than .any(), because not doing so
|
||||
// brings up a fair amount of extra complexity (we can't make the decision on
|
||||
// whether to walk out statically).
|
||||
l.slice().iter().all(|i| i.is_featureless_host_selector_or_pseudo_element())
|
||||
},
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the value as a combinator if applicable, None otherwise.
|
||||
pub fn as_combinator(&self) -> Option<Combinator> {
|
||||
match *self {
|
||||
|
@ -0,0 +1,23 @@
|
||||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<title>:host and nesting (basic) </title>
|
||||
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
|
||||
<link rel="author" title="Mozilla" href="https://mozilla.org">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-nesting/#nest-selector">
|
||||
<link rel="match" href="/css/reference/ref-filled-green-100px-square-only.html">
|
||||
<p>Test passes if there is a filled green square.</p>
|
||||
<div id="host"></div>
|
||||
<script>
|
||||
host.attachShadow({mode: "open"}).innerHTML = `
|
||||
<style>
|
||||
:host {
|
||||
.nested {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-color: green;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<div class="nested"></div>
|
||||
`;
|
||||
</script>
|
@ -0,0 +1,22 @@
|
||||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<title>:host and nesting (bare declarations)</title>
|
||||
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
|
||||
<link rel="author" title="Mozilla" href="https://mozilla.org">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-nesting/#nest-selector">
|
||||
<link rel="match" href="/css/reference/ref-filled-green-100px-square-only.html">
|
||||
<p>Test passes if there is a filled green square.</p>
|
||||
<div id="host"></div>
|
||||
<script>
|
||||
host.attachShadow({mode: "open"}).innerHTML = `
|
||||
<style>
|
||||
:host {
|
||||
@media (width >= 0) {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-color: green;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
`;
|
||||
</script>
|
@ -0,0 +1,26 @@
|
||||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<title>:host and nesting (combined with something else)</title>
|
||||
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
|
||||
<link rel="author" title="Mozilla" href="https://mozilla.org">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-nesting/#nest-selector">
|
||||
<link rel="match" href="/css/reference/ref-filled-green-100px-square-only.html">
|
||||
<p>Test passes if there is a filled green square.</p>
|
||||
<div id="host"></div>
|
||||
<script>
|
||||
host.attachShadow({mode: "open"}).innerHTML = `
|
||||
<style>
|
||||
.nested {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-color: green;
|
||||
}
|
||||
:host(#not-host), #host {
|
||||
.nested {
|
||||
background-color: red;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<div class="nested"></div>
|
||||
`;
|
||||
</script>
|
@ -0,0 +1,25 @@
|
||||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<title>:host and nesting (combined with something else, bare declarations)</title>
|
||||
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
|
||||
<link rel="author" title="Mozilla" href="https://mozilla.org">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-nesting/#nest-selector">
|
||||
<link rel="match" href="/css/reference/ref-filled-green-100px-square-only.html">
|
||||
<p>Test passes if there is a filled green square.</p>
|
||||
<div id="host"></div>
|
||||
<script>
|
||||
host.attachShadow({mode: "open"}).innerHTML = `
|
||||
<style>
|
||||
:host {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-color: green;
|
||||
}
|
||||
:host(#not-host), #host {
|
||||
@media (width >= 0) {
|
||||
background-color: red;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
`;
|
||||
</script>
|
@ -0,0 +1,24 @@
|
||||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<title>:host and nesting (with pseudos)</title>
|
||||
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
|
||||
<link rel="author" title="Mozilla" href="https://mozilla.org">
|
||||
<link rel="help" href="https://drafts.csswg.org/css-nesting/#nest-selector">
|
||||
<link rel="match" href="/css/reference/ref-filled-green-100px-square-only.html">
|
||||
<p>Test passes if there is a filled green square.</p>
|
||||
<div id="host"></div>
|
||||
<script>
|
||||
host.attachShadow({mode: "open"}).innerHTML = `
|
||||
<style>
|
||||
:host {
|
||||
&::before {
|
||||
display: block;
|
||||
content: "";
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-color: green;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
`;
|
||||
</script>
|
21
testing/web-platform/tests/css/css-scoping/host-is-001.html
Normal file
21
testing/web-platform/tests/css/css-scoping/host-is-001.html
Normal file
@ -0,0 +1,21 @@
|
||||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<title>:host and :is (basic) </title>
|
||||
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
|
||||
<link rel="author" title="Mozilla" href="https://mozilla.org">
|
||||
<link rel="help" href="https://drafts.csswg.org/selectors/#featureless">
|
||||
<link rel="match" href="/css/reference/ref-filled-green-100px-square-only.html">
|
||||
<p>Test passes if there is a filled green square.</p>
|
||||
<div id="host"></div>
|
||||
<script>
|
||||
host.attachShadow({mode: "open"}).innerHTML = `
|
||||
<style>
|
||||
:is(:host) .nested {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-color: green;
|
||||
}
|
||||
</style>
|
||||
<div class="nested"></div>
|
||||
`;
|
||||
</script>
|
20
testing/web-platform/tests/css/css-scoping/host-is-002.html
Normal file
20
testing/web-platform/tests/css/css-scoping/host-is-002.html
Normal file
@ -0,0 +1,20 @@
|
||||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<title>:host and :is (basic)</title>
|
||||
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
|
||||
<link rel="author" title="Mozilla" href="https://mozilla.org">
|
||||
<link rel="help" href="https://drafts.csswg.org/selectors/#featureless">
|
||||
<link rel="match" href="/css/reference/ref-filled-green-100px-square-only.html">
|
||||
<p>Test passes if there is a filled green square.</p>
|
||||
<div id="host"></div>
|
||||
<script>
|
||||
host.attachShadow({mode: "open"}).innerHTML = `
|
||||
<style>
|
||||
:is(:host) {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-color: green;
|
||||
}
|
||||
</style>
|
||||
`;
|
||||
</script>
|
24
testing/web-platform/tests/css/css-scoping/host-is-003.html
Normal file
24
testing/web-platform/tests/css/css-scoping/host-is-003.html
Normal file
@ -0,0 +1,24 @@
|
||||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<title>:host and :is() (combined with something else)</title>
|
||||
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
|
||||
<link rel="author" title="Mozilla" href="https://mozilla.org">
|
||||
<link rel="help" href="https://drafts.csswg.org/selectors/#featureless">
|
||||
<link rel="match" href="/css/reference/ref-filled-green-100px-square-only.html">
|
||||
<p>Test passes if there is a filled green square.</p>
|
||||
<div id="host"></div>
|
||||
<script>
|
||||
host.attachShadow({mode: "open"}).innerHTML = `
|
||||
<style>
|
||||
.nested {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-color: green;
|
||||
}
|
||||
:is(:host(#not-host), #host) .nested {
|
||||
background-color: red;
|
||||
}
|
||||
</style>
|
||||
<div class="nested"></div>
|
||||
`;
|
||||
</script>
|
23
testing/web-platform/tests/css/css-scoping/host-is-004.html
Normal file
23
testing/web-platform/tests/css/css-scoping/host-is-004.html
Normal file
@ -0,0 +1,23 @@
|
||||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<title>:host and :is (combined with something else)</title>
|
||||
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
|
||||
<link rel="author" title="Mozilla" href="https://mozilla.org">
|
||||
<link rel="help" href="https://drafts.csswg.org/selectors/#featureless">
|
||||
<link rel="match" href="/css/reference/ref-filled-green-100px-square-only.html">
|
||||
<p>Test passes if there is a filled green square.</p>
|
||||
<div id="host"></div>
|
||||
<script>
|
||||
host.attachShadow({mode: "open"}).innerHTML = `
|
||||
<style>
|
||||
:host {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-color: green;
|
||||
}
|
||||
:is(:host(#not-host), #host) {
|
||||
background-color: red;
|
||||
}
|
||||
</style>
|
||||
`;
|
||||
</script>
|
22
testing/web-platform/tests/css/css-scoping/host-is-005.html
Normal file
22
testing/web-platform/tests/css/css-scoping/host-is-005.html
Normal file
@ -0,0 +1,22 @@
|
||||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<title>:host and :is() (with pseudos)</title>
|
||||
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
|
||||
<link rel="author" title="Mozilla" href="https://mozilla.org">
|
||||
<link rel="help" href="https://drafts.csswg.org/selectors/#featureless">
|
||||
<link rel="match" href="/css/reference/ref-filled-green-100px-square-only.html">
|
||||
<p>Test passes if there is a filled green square.</p>
|
||||
<div id="host"></div>
|
||||
<script>
|
||||
host.attachShadow({mode: "open"}).innerHTML = `
|
||||
<style>
|
||||
:is(:host)::before {
|
||||
display: block;
|
||||
content: "";
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-color: green;
|
||||
}
|
||||
</style>
|
||||
`;
|
||||
</script>
|
Loading…
Reference in New Issue
Block a user