问题
I'll try to explain this as simple as possible:
For this example I want the arrow of each box to take the background colour of its respective box automatically by only adding red, black, grey classes to the box. I could easily do:
.box.red {
&:before {
...
border-bottom: 1px solid $red;
}
}
.box.black {
&:before {
...
border-bottom: 1px solid $black;
}
}
.box.grey {
&:before {
...
border-bottom: 1px solid $grey;
}
}
But this implies that for every different colour I create I'll have to change the arrow colour manually. If in the future I want to add a green box for example I'll have to change its arrow colour to green in the CSS. Is there a way in Sass to make it so I don't need to worry with changing the arrow colour every time the box background colour changes?
Thank you.
See DEMO
回答1:
Since your element will have solid color you can create the arrow with a rectangle on where you apply rotation in order to achieve the layout then you can use inherit
for background
.box {
position: relative;
width: 100px;
height: 100px;
margin-bottom: 40px;
background:red;
}
.box::before {
content:"";
position:absolute;
width:30px;
height:30px;
top:100%;
left:20px;
transform:translateY(-50%) rotateX(40deg) rotate(45deg);
background:inherit;
}
.blue {
background:blue;
}
.green {
background:green;
}
<div class="box">
</div>
<div class="box blue">
</div>
<div class="box green">
</div>
You can also rely on CSS variable and you will be able to change the color only once even if it's used in many places.
Here is another way to create the shape where you can easily control the color, size and position of the arrow:
.box {
position: relative;
width: 100px;
height: 100px;
padding-bottom: var(--s,20px);
margin-bottom:10px;
background:
linear-gradient(to top right,transparent 49.8%,var(--c,red) 50%) var(--p,20px) 100%,
linear-gradient(to top left, transparent 49.8%,var(--c,red) 50%) calc(var(--p,20px) + var(--s,20px)) 100%,
var(--c,red) content-box;
background-size:var(--s,20px) var(--s,20px);
background-repeat:no-repeat;
}
.blue {
--c:blue;
--s:15px;
--p:40px;
}
.green {
--c:green;
--s:10px;
--p:60px;
}
<div class="box"></div>
<div class="box blue"></div>
<div class="box green"></div>
You can easily achieve the same logic to your code:
.box {
position: relative;
width: 100px;
height: 100px;
margin-bottom: 40px;
background:var(--c,green);
}
.box:before {
content: ' ';
border: solid transparent;
border-bottom: 1px solid var(--c,green);
border-width: 15px;
height: 0;
position: absolute;
transform: rotate(180deg);
width: 0;
bottom: -30px;
left: 20px;
}
.red {
--c: #f00;
}
.black {
--c: #000;
}
.grey {
--c: #aaa;
}
<div class="box red"></div>
<div class="box black"></div>
<div class="box grey"></div>
<div class="box "></div>
回答2:
To get that effect, the best approach would be to use css inheritance. Since the parent box has the background set, then we can only inherit the value on the :after
pseudo-element background
property as well - we can't use it on the border color. Fortunately, we can get the "triangular arrow" effect without using border, but with regular background and clip-path
rule instead. The full example is shown in the snippet below:
.box {
position: relative;
width: 100px;
height: 100px;
margin-bottom: 40px;
}
.box:before {
content: '';
position: absolute;
background: inherit;
clip-path: polygon(0 0, 30px 0, 15px 15px);
width: 30px;
height: 15px;
bottom: -16px;
left: 20px;
}
.red {
background: #f00;
}
.black {
background: #000;
}
.grey {
background: #aaa;
}
<div class="box red"></div>
<div class="box black"></div>
<div class="box grey"></div>
Update for IE and Edge
If all of these are true:
- Compatibility with IE and Edge is your concern
- You can handle a bit of micro-duplication in your css rules
- You don't intend to have borders on your
.box
elements
then you can apply border-bottom-color
to the .box
class and inherit it in the :after
pseudo element definition as follows:
.box {
position: relative;
width: 100px;
height: 100px;
margin-bottom: 40px;
}
.box:before {
content: ' ';
border-bottom: 1px solid;
border-bottom-color: inherit;
border-left: 1px solid transparent;
border-right: 1px solid transparent;
border-top: 1px solid transparent;
border-width: 15px;
height: 0;
position: absolute;
transform: rotate(180deg);
width: 0;
bottom: -30px;
left: 20px;
}
.red {
background: #f00;
border-bottom-color: #f00;
}
.black {
background: #000;
border-bottom-color: #000;
}
.grey {
background: #aaa;
border-bottom-color: #aaa;
}
<div class="box red"></div>
<div class="box black"></div>
<div class="box grey"></div>
回答3:
This can be achieved using a SCSS mixin. See codepen here
In the linked codepen, there's a variable that defines your colors:
$color-list: (
"red": #f00,
"black": #000,
"grey": #aaa,
);
This variable is the one-and-only place that the color needs to be defined. You can easily add more colors if more boxes are needed.
There is then a @mixin
that adds the background-color
and the colored border:
@mixin box-color() {
@each $color in map-keys($color-list) {
&.#{$color} {
background: map-get($color-list, $color);
&:before {
content: ' ';
border: solid transparent;
border-bottom: 1px solid map-get($color-list, $color);
border-width: 15px;
height: 0;
position: absolute;
transform: rotate(180deg);
width: 0;
bottom: -30px;
left: 20px;
}
}
}
}
The mixin basically adds a new class for each color in the $color-list
, and populates the class with the appropriate color for the background and pseudo element.
The mixin simply has to be included in the .box
class:
.box {
@include box-color();
position: relative;
width: 100px;
height: 100px;
margin-bottom: 40px;
}
来源:https://stackoverflow.com/questions/55090673/box-arrow-to-take-background-colour-of-respective-box