我想做一个星级控制,但我似乎无法找到一种方法来选择悬停时所有以前的兄弟姐妹。这种东西是否存在或者我必须使用javascript?
span {
display:inline-block;
width: 32px;
height: 32px;
background-color:#eee;
}
span:hover {
background-color:red;
}Run Code Online (Sandbox Code Playgroud)
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>Run Code Online (Sandbox Code Playgroud)
Dav*_*mas 11
“我似乎无法找到一种在悬停时选择所有先前兄弟姐妹的方法”
不幸的是,CSS 只能定位并因此选择 DOM 中的后续元素。值得庆幸的是,这当然可以用 CSS 模拟或用 JavaScript 启用。
首先,CSS 方法需要 CSS Grid 或 CSS Flexbox 来调整页面上元素的顺序:
*,
::before,
::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
div {
/* to place a 1em gap between items, applicable
to both Grid and Flexbox: */
gap: 1em;
width: 80vw;
margin: 1em auto;
}
div.withFlex {
/* Using flexbox layout: */
display: flex;
/* In the HTML you might have noticed that the '5 star'
element comes before the '1 star'...'4 star' element,
this property reverses the order of the flex-items
(the <span> elements) in the flex-box layout: */
flex-direction: row-reverse;
/* spacing the elements apart, this approach places the
available space (after the element-sizes have been
calculated) between the elements: */
justify-content: space-between;
}
div.withFlex span {
border: 1px solid #000;
flex: 1 1 auto;
}
/* here we use Grid layout: */
div.withGrid {
display: grid;
/* we force the grid-items (the <span> elements) to
flow into columns rather than rows: */
grid-auto-flow: column;
/* here we cause the layout - again - to be reversed,
flowing from right-to-left: */
direction: rtl;
}
div.withGrid span {
border: 1px solid currentcolor;
text-align: left;
}
/* here we select the <span> that the user hovers over,
plus any subsequent siblings, and style them differently;
as the subsequent elements appear - visually - before the
hovered-<span> this gives the illusion that we're selecting
previous elements in the DOM: */
span:hover,
span:hover~span {
color: #f90;
border-color: currentcolor;
}Run Code Online (Sandbox Code Playgroud)
<div class="withFlex">
<span>5 stars</span>
<span>4 stars</span>
<span>3 stars</span>
<span>2 stars</span>
<span>1 star</span>
</div>
<div class="withGrid">
<span>5 stars</span>
<span>4 stars</span>
<span>3 stars</span>
<span>2 stars</span>
<span>1 star</span>
</div>Run Code Online (Sandbox Code Playgroud)
除了上述之外,假设您希望元素能够保持被选中状态——同时仍然使用 CSS 和 HTML——那么使用 some <input>and<label>元素也是可能的:
*,
::before,
::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
div {
/* to place a 1em gap between items, applicable
to both Grid and Flexbox: */
gap: 1em;
width: 80vw;
margin: 1em auto;
}
input[type=radio] {
position: absolute;
top: -10000px;
left: -10000px
}
label {
border: 1px solid currentcolor;
cursor: pointer;
}
div.withFlex {
/* Using flexbox layout: */
display: flex;
/* In the HTML you might have noticed that the '5 star'
element comes before the '1 star'...'4 star' element,
this property reverses the order of the flex-items
(the <span> elements) in the flex-box layout: */
flex-direction: row-reverse;
/* spacing the elements apart, this approach places the
available space (after the element-sizes have been
calculated) between the elements: */
justify-content: space-between;
}
div.withFlex label {
flex: 1 1 auto;
}
/* here we use Grid layout: */
div.withGrid {
display: grid;
/* we force the grid-items (the <span> elements) to
flow into columns rather than rows: */
grid-auto-flow: column;
/* here we cause the layout - again - to be reversed,
flowing from right-to-left: */
direction: rtl;
}
div.withGrid label {
direction: ltr;
}
/* here we select the <span> that the user hovers over,
plus any subsequent siblings, and style them differently;
as the subsequent elements appear - visually - before the
hovered-<span> this gives the illusion that we're selecting
previous elements in the DOM: */
label:hover,
label:hover~label {
color: #f90f;
border-color: currentcolor;
}
/* here we select all <label> elements that follow an <input>
of type=radio (using an attribute-selector) which is checked: */
input[type=radio]:checked~label {
color: #f90c;
border-color: currentcolor;
}Run Code Online (Sandbox Code Playgroud)
<div class="withFlex">
<!-- because we're styling the <label> elements based
on the state (checked/unchecked) of the <input>
elements we have to place the relevant <input>
before the affected <label> in the DOM; which is
why they precede the element that's being styled.
While the :focus-within pseudo-class exists there
is (as yet) no comparable ':checked-within', and
the :has() pseudo-class does not yet (in 2020)
exist; JavaScript could be used but this demo is
to show HTML/CSS methods rather than JS: -->
<input id="withFlexInput5" type="radio" name="rating1" />
<label for="withFlexInput5">
5 stars
</label>
<input id="withFlexInput4" type="radio" name="rating1" />
<label for="withFlexInput4">
4 stars
</label>
<input id="withFlexInput3" type="radio" name="rating1" />
<label for="withFlexInput3">
3 stars
</label>
<input id="withFlexInput2" type="radio" name="rating1" />
<label for="withFlexInput2">
2 stars
</label>
<input id="withFlexInput1" type="radio" name="rating1" />
<label for="withFlexInput1">
1 star
</label>
</div>
<div class="withGrid">
<input id="withGridInput5" type="radio" name="rating2" />
<label for="withGridInput5">
5 stars
</label>
<input id="withGridInput4" type="radio" name="rating2" />
<label for="withGridInput4">
4 stars
</label>
<input id="withGridInput3" type="radio" name="rating2" />
<label for="withGridInput3">
3 stars
</label>
<input id="withGridInput2" type="radio" name="rating2" />
<label for="withGridInput2">
2 stars
</label>
<input id="withGridInput1" type="radio" name="rating2" />
<label for="withGridInput1">
1 stars
</label>
</div>Run Code Online (Sandbox Code Playgroud)
// obtain all spans from DOM
const spans = document.querySelectorAll('span');
// set a variable at global scope as indicator
let flag = false;
// add event listener to each span
spans.forEach((sp, j)=>{
sp.addEventListener('click', ()=>{
// if clicked, then not dismissing the background colour after mouse leave
flag = true;
// reassign all spans back to original grey
spans.forEach(dsp=>{
dsp.style.backgroundColor = '#eee';
});
// assign bg to red of the spans from 0 to clicked index
Array.from(new Array(j+1), (x, i) => i).forEach(ind=>{
spans[ind].style.backgroundColor = 'red';
});
});
// redo if mouse enters
sp.addEventListener('mouseenter', ()=>{
flag = false;
});
// if any span is hovered
sp.addEventListener('mouseover', ()=>{
// reassign all spans back to original grey
spans.forEach(dsp=>{
dsp.style.backgroundColor = '#eee';
});
// assign bg to red of the spans from 0 to clicked index
Array.from(new Array(j+1), (x, i) => i).forEach(ind=>{
spans[ind].style.backgroundColor = 'red';
});
});
// in moseleave, only save the background colour if click happened
sp.addEventListener('mouseleave', ()=>{
if(!flag){
spans.forEach(dsp=>{
dsp.style.backgroundColor = '#eee';
});
}
});
});Run Code Online (Sandbox Code Playgroud)
span {
display:inline-block;
width: 32px;
height: 32px;
background-color:#eee;
}
span:hover {
background-color:red;
opacity: 0.8;
cursor: pointer;
}Run Code Online (Sandbox Code Playgroud)
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>Run Code Online (Sandbox Code Playgroud)
这里还有其他使用Flexbox和CSS Grid 的CSS 解决方案。
但是,如果你很高兴去老派,同样的效果可以实现:
float: right;
Run Code Online (Sandbox Code Playgroud)
工作示例:
float: right;
Run Code Online (Sandbox Code Playgroud)
div {
float: left;
width: 180px;
}
span {
float: right;
display: inline-block;
width: 32px;
height: 32px;
margin-left: 4px;
background-color: #eee;
cursor: pointer;
}
span:hover,
span:hover ~ span {
background-color: red;
}Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1279 次 |
| 最近记录: |