Mo.*_*Mo. 12 css background linear-gradients css3 background-position
有没有办法background-position取出百分比值?目前我的按钮仅适用于一个明确的价值观width和background-position.
body {
min-height: 100vh;
display: flex;
flex-direction: column;
justify-content: space-around;
align-items: center;
}
.button {
display: flex;
justify-content: center;
align-items: center;
text-decoration: none;
color: white;
font-weight: bold;
width: 350px;
height: 50px;
border: 1px solid green;
transition: background 0.5s;
background-repeat: no-repeat;
background-image: linear-gradient(to left, #2484c6, #1995c8 51%, #00bbce), linear-gradient(to right, #2484c6 0%, #1995c8 51%, #00bbce 76%);
}
.button-pixel {
background-position: -350px 0px, 0px 0px;
}
.button-pixel:hover {
background-position: 0px 0px, 350px 0px;
}
.button-percentage {
background-position: -100% 0px, 0px 0px;
}
.button-percentage:hover {
background-position: 0% 0px, 100% 0px;
}Run Code Online (Sandbox Code Playgroud)
<a href="#" class="button button-pixel">In Pixel</a>
<a href="#" class="button button-percentage">In Percentage</a>Run Code Online (Sandbox Code Playgroud)
Tem*_*fif 30
使用渐变作为背景时,使用的所有百分比值background-position 都是等效的,因此您不会看到任何差异.您需要指定background-size与容器大小不同的内容:
body {
display: flex;
flex-direction: column;
justify-content: space-around;
align-items: center;
min-height:90vh;
}
.button {
text-decoration: none;
color: white;
font-weight: bold;
width: 350px;
height: 50px;
text-align:center;
transition: background 0.5s;
background-repeat: no-repeat;
background-image:
linear-gradient(to left, #2484c6, #1995c8 51%, #00bbce),
linear-gradient(to right, #2484c6 0%, #1995c8 51%, #00bbce 76%);
background-size:200% 100%; /*Changed this*/
}
.button-pixel {
background-position: -350px 0px, 0px 0px;
}
.button-pixel:hover {
background-position: 0px 0px, 350px 0px;
}
.button-percentage {
background-position: 100% 0px, 0px 0px;
}
.button-percentage:hover {
background-position: 0% 0px, 100% 0px;
}Run Code Online (Sandbox Code Playgroud)
<a href="#" class="button button-pixel">Pixel</a>
<a href="#" class="button button-percentage">Percentage</a>Run Code Online (Sandbox Code Playgroud)
让我们使用经典图像来解释它是如何background-position工作的.
使用像素值时,无论大小如何,引用都是图像的左上角.这就像使用top/ left定位元素一样:
.b {
width:200px;
height:200px;
background:url(https://picsum.photos/100/100?image=1069) no-repeat;
border:1px solid;
background-position:0 0;
position:relative;
animation:back 5s infinite linear alternate;
}
.b:before {
content:"";
position:absolute;
top:0;
left:0;
width:10px;
height:10px;
background:red;
animation:change 5s infinite linear alternate;
}
@keyframes back{to{background-position:200px 200px;}}
@keyframes change{to{top:200px; left:200px;}}Run Code Online (Sandbox Code Playgroud)
<div class="b"></div>Run Code Online (Sandbox Code Playgroud)
使用百分比值时,参考值与使用像素值时的参考值不同; 它不再是上/左上角:
.b {
width:200px;
height:200px;
background-image:url(https://picsum.photos/100/100?image=1069);
border:1px solid;
background-position:0% 0%;
background-repeat:no-repeat;
position:relative;
animation:back 5s infinite linear alternate;
}
.b:before {
content:"";
position:absolute;
top:0;
left:0;
width:10px;
height:10px;
background:red;
animation:change 5s infinite linear alternate;
}
@keyframes back{to{background-position:100% 100%;}}
@keyframes change{to{top:200px; left:200px;}}Run Code Online (Sandbox Code Playgroud)
<div class="b"></div>Run Code Online (Sandbox Code Playgroud)
在这种情况下,我们需要考虑两个参数:容器的大小和图像的大小.这是一个如何工作的例证(我采取了background-position相同的30% 30%):
首先,我们考虑图像以找到我们将用于放置图像的参考点.考虑到图像的大小(如绿线所定义),它是位于顶部/左侧角落的图像内部的点.然后,我们把该点的容器内,在从顶部/左上角考虑容器的大小.30% 30%30% 30%
从这个逻辑来看,我们可以清楚地识别出琐碎的案例
50% 50%(中) 100% 100%(右下) 100% 0%(右上)
现在很清楚,如果图像的大小等于容器的大小,那么就不会发生任何事情,因为我们为了放置图像而计算的点将保留在其初始位置,因此图像将不会移动,因为所有这些职位是等同的.
.b {
width:200px;
height:200px;
background:url(https://picsum.photos/200/200?image=1069) no-repeat;
border:1px solid;
background-position:0% 0%;
position:relative;
animation:back 5s infinite linear alternate;
}
.b:before {
content:"";
position:absolute;
top:0;
left:0;
width:10px;
height:10px;
background:red;
animation:change 5s infinite linear alternate;
}
@keyframes back{to{background-position:100% 100%;}}
@keyframes change{to{top:100%; left:100%;}}Run Code Online (Sandbox Code Playgroud)
<div class="b"></div>Run Code Online (Sandbox Code Playgroud)
应用于渐变时,上述逻辑是相同的,因为渐变被视为图像,默认情况下,如果未指定a background-size,渐变的大小将是其容器的大小,与使用图像时不同.
如果我们指的是规范的background-size,我们就可以看到你的问题是如何产生的:
注意:
如果两个值都是自动的,那么应该使用图像的固有宽度和/或高度 (如果有的话),缺失的维度(如果有的话)表现为如上所述的自动.如果图像既没有固有宽度也没有固有高度,则其大小确定为包含.
和:
包含
缩放图像,同时保持其固有的纵横比 (如果有的话)到最大尺寸,使得其宽度和高度都可以适合背景定位区域.
并且:
位图图像(例如JPG)始终具有固有的尺寸和比例.
CSS
<gradient>小号有没有内在的尺寸或内在的比例.REF
An image always has intrinsic values, so in most cases it won't have the same size as its container, so background-position with percentage units will have an effect. But gradients don't have intrinsic values, thus a gradient's dimensions will be equal to the size of its container, and background-position with percentage values will never work unless we specify a background-size different from its container's dimensions.
We saw in the above examples how background-size works when using values between 0% and 100%, but what about using negative values or a value bigger than 100%? The logic is the same, but finding the reference point will be more tricky.
Negative values (< 0%)
Let's suppose we want to place a background at -50% 0. In this case the reference point will be outside the image. Here is an example:
.b {
width:200px;
height:200px;
border:1px solid;
background:url(https://picsum.photos/100/100?image=1069) -50% 0/100px 100px no-repeat;
}Run Code Online (Sandbox Code Playgroud)
<div class="b"></div>Run Code Online (Sandbox Code Playgroud)
As we can see in the illustration, we first consider -50% of the image, which is -50px, in order to define our reference point (i.e., -50px from the left edge of the image). Then we place that point at -50% considering the size of the container (-100px from the left edge of the container). Then we draw the image, and we obtain the above result. Only 100px of the image is visible.
We may also notice that negative percentage values will behave the same as negative fixed values when the size of the image is smaller than the size of the container (both will shift the image to the left). In this case -50% 0 is the same as -50px 0.
.b {
width:200px;
height:200px;
display:inline-block;
border:1px solid;
background:url(https://picsum.photos/100/100?image=1069) -50% 0/100px 100px no-repeat;
}
.a{
background:url(https://picsum.photos/100/100?image=1069) -50px 0/100px 100px no-repeat;
}Run Code Online (Sandbox Code Playgroud)
<div class="b">
</div>
<div class="b a">
</div>Run Code Online (Sandbox Code Playgroud)
If for example we increase the image size to 150px 150px, -50% 0 will be the same as -25px 0.
When we make the size bigger than the container, negative values will start shifting the image to the right (like with positive pixel values), which is logical since the 50% of the image will increase while the 50% of the container will remain the same.
If we consider the previous illustration, it's like increasing the top green line until it's bigger than the bottom one. So the sign only is not enough to know how the background image will be shifted; we need to also consider the size.
.b{
width:200px;
height:200px;
border:1px solid;
background:url(https://picsum.photos/300/300?image=1069) -50% 0/50px 50px no-repeat;
animation:change 2s linear infinite alternate;
}
@keyframes change{
to {background-size:300px 300px}
}Run Code Online (Sandbox Code Playgroud)
<div class="b">
</div>Run Code Online (Sandbox Code Playgroud)
Big values (> 100%)
Same logic as previously: if we define a background at 150% 0, then we consider our reference point 150% from the left edge (or 50% from the right edge), then we place it 150% from the left edge of the container.
.b {
width:200px;
height:200px;
border:1px solid;
background:linear-gradient(to right,red,blue) -50% 0/50px 150px no-repeat;
animation:change 2s linear infinite alternate;
}
@keyframes change{
to {background-size:300px 150px}
}Run Code Online (Sandbox Code Playgroud)
<div class="b">
</div>Run Code Online (Sandbox Code Playgroud)
In this case, 150% 0 is equivalent to 150px 0, and if we start increasing the background size we will have the same behavior as previously demonstrated:
.b {
width:200px;
height:200px;
border:1px solid;
background:url(https://picsum.photos/100/100?image=1069) 150% 0/100px 100px no-repeat;
}Run Code Online (Sandbox Code Playgroud)
<div class="b"></div>Run Code Online (Sandbox Code Playgroud)
Using values outside the range [0% 100%] allows us to hide the background image, but how do we find the exact values in order to completely hide the image?
Let's consider the below illustration:
Our image has a width Ws and the container a width Wp and we need to find the value of p. From the figure we can obtain the following formula:
.b {
width:200px;
height:200px;
border:1px solid;
background:url(https://picsum.photos/300/300?image=1069) 150% 0/50px 50px no-repeat;
animation:change 2s infinite linear alternate;
}
@keyframes change {
to {background-size:300px 300px}
}Run Code Online (Sandbox Code Playgroud)
If the container size is 200px and the image is 100px then p is 1 so 100% (we add of course the negative sign and it's -100%).
We can make this more generic if we consider percentage values with background-size instead of fixed values. Suppose the background-size is s%. Then we will have S%, and the formula will be
<div class="b"></div>Run Code Online (Sandbox Code Playgroud)
Adding the negative sign it will be Ws = Wp * s (s in [0,1] and S=s*100%).
Now if we want to hide the image on the right side, we do the same logic on the right (we consider a mirror of the previous illustration), but since we will always consider the left edge to find the percentage we need to add p = s / (s - 1).
The new percentage is 100%, and the formula will be p'%.
Here is an animation to illustrate the above calculation:
p * Wp = p * Ws + Ws <=> p = Ws/(Wp - Ws) where p in [0,1]
Run Code Online (Sandbox Code Playgroud)
p = Ws/(Wp - Ws) <=> p = s / (1 - s)
Run Code Online (Sandbox Code Playgroud)
Let's calculate some values:
When 100% + p%, we have a p' = 1 + p --> p' = 1 + s / (1 - s) = 1 / (1 - s) equal to s=0.5, and the percentage values will be from background-size to 50%. In this case, we started with a negative value and ended with a positive one because the size of the image is smaller than the size of the container. If we consider the last case (-100%) the 200% is equal to s=2, and the percentage values will be from background-size to 200%. We started with a positive value and ended with a negative one because the size of the image is bigger than the size of the container.
This confirms what we said previously: to shift an image to the left we need negative values if the size is small, but we need positive values if the size is big (same thing for the right).
Let's define a way to calculate percentage values based on pixel values, or vice versa (i.e. the formula to convert between both). To do this we simply need to consider the reference points.
When using pixel values, we will consider the blue lines and we will have 200%.
When using percentage values, we will consider the green lines and we will have -100%.
The formula will be like follow : background-position:X Y where background-position:Px Py is the width of the image and Y + Py * Ws = Py * Wp is the width of the container (same formula for the X axis considering height).
We will have Ws. From this formula we can validate two points as explained previously:
Wp, the formula is no longer valid, which confirms that percentage values have no effect when the size of the image is the same as the container; thus there is no relation between pixel and percentage values.Y = Py * (Wp - Ws) and Wp = Ws will have the same sign when Y and will have opposite sign when Py. This confirms that percentage value behave differently depending the size of the image.We can also express the formula differently if we consider percentage value of Wp > Ws. We will have Wp < Ws.
Here is an animation to illustrate the above calculation:
.b {
width:200px;
height:50px;
margin:5px;
border:1px solid;
background:linear-gradient(to right,red,blue) no-repeat;
background-size:calc(var(--s) * 100%) 100%;
animation:change 4s linear infinite alternate;
}
@keyframes change{
from { /*Hide on the left*/
background-position:calc(var(--s)/(var(--s) - 1) * 100%)
}
to { /*Hide on the right*/
background-position:calc(1/(1 - var(--s)) * 100%)
}
}Run Code Online (Sandbox Code Playgroud)
<div class="b" style="--s:0.5">
</div>
<div class="b" style="--s:0.8">
</div>
<div class="b" style="--s:2">
</div>Run Code Online (Sandbox Code Playgroud)
In the above calculations, we always considered the top/left corner of the image and the container in order to apply our logic either for pixel values or percentage values. This reference can be changed by adding more values to background-size.
By default Y = Py * Wp * (1-s) is equivalent to background-position (position at background-position: X Y from the background-position: left X top Y and at X from the left). By adjusting Y and/or top we change the reference and how the image is placed. Here are some examples:
.b {
width:200px;
height:50px;
margin:5px;
border:1px solid;
background:linear-gradient(to right,red,blue) no-repeat;
background-size:calc(var(--s) * 100%) 100%;
animation:percentage 2s linear infinite alternate;
}
.box.a {
animation-name:pixel;
}
@keyframes percentage{
from { background-position:-50%;}
to { background-position:150%;}
}
@keyframes pixel{
from { background-position:calc(-0.5 * 200px * (1 - var(--s))) }
to { background-position:calc(1.5 * 200px * (1 - var(--s)));}
}Run Code Online (Sandbox Code Playgroud)
<div class="b" style="--s:0.5">
</div>
<div class="b a" style="--s:0.5">
</div>
<div class="b" style="--s:2">
</div>
<div class="b a" style="--s:2">
</div>Run Code Online (Sandbox Code Playgroud)
It's clear that for the top value we can only use left and X (the horizontal position) and with the left value we can only use right and Y (the vertical position). With all the different combinations we can logically obtain the 4 different corners.
This feature is also useful in order to optimize some calculation. In the example of the special cases section, we did a first calculation to hide the image on the left then another one to hide it on the right. If we consider changing the reference we only need to do one calculation. We take the formula used for the left side and we use the same on the right side.
Here is the new version:
.b {
width:150px;
height:150px;
display:inline-block;
background:url(https://picsum.photos/70/70?image=1069) no-repeat;
border:1px solid;
position:relative;
}
body {
margin:0;
}Run Code Online (Sandbox Code Playgroud)
<div class="b"></div>
<div class="b" style="background-position:left 0 bottom 0"></div>
<div class="b" style="background-position:right 0 bottom 0"></div>
<div class="b" style="background-position:right 0 top 0"></div>
<div class="b" style="background-position:right 10% top 30%"></div>
<div class="b" style="background-position:right 10% bottom 30%"></div>
<div class="b" style="background-position:right 10px top 20px"></div>
<div class="b" style="background-position:left 50% bottom 20px"></div>Run Code Online (Sandbox Code Playgroud)
For bottom we will no more animate from top to s=0.5 BUT it will be from -100% to 200%.
Here is another example using pixel values where we can clearly see how easy is to deal with the calculation when changing the reference:
.b {
width:200px;
height:50px;
margin:5px;
border:1px solid;
background:linear-gradient(to right,red,blue) no-repeat;
background-size:calc(var(--s) * 100%) 100%;
animation:change 4s linear infinite alternate;
}
@keyframes change{
from {
background-position:left calc(var(--s)/(var(--s) - 1) * 100%) top 0
}
to {
background-position:right calc(var(--s)/(var(--s) - 1) * 100%) top 0
}
}Run Code Online (Sandbox Code Playgroud)
<div class="b" style="--s:0.5">
</div>
<div class="b" style="--s:0.8">
</div>
<div class="b" style="--s:2">
</div>Run Code Online (Sandbox Code Playgroud)
It would be tricky to achieve the same animation by keeping the same reference. So if we want to do a symmetrical animation we do our logic on one side and use the same on the other side by changing the reference.
In CSS3 we can use left -100% in order to do some complex calculation that involves different units. For example, we can write right -100% and the browser will calculate the computed value considering how each unit works and we will end with a pixel value (for this case).
What about calc()? If we write width:calc(100px + 20% + 12em), will this be evaluated to a percentage value or a pixel value? will the pixel value be converted to percentage or the opposite?
The result will not be converted to a pixel value or a percentage value, but rather both will be used together! background-position has a special behavior when mixing percentage and pixel values inside calc(50% + 50px) and the logic is as follows:
So background-position means: center the image, then shift it by 50px to the left.
This feature can simplify a lot of calculation. Here is an example:
.b {
width:200px;
height:200px;
background:url(https://picsum.photos/100/100?image=1069) no-repeat;
border:1px solid;
background-repeat:no-repeat;
animation:change 2s infinite linear;
}
@keyframes change{
0%{background-position:left 20px top 20px;}
25%{background-position:right 20px top 20px;}
50%{background-position:right 20px bottom 20px;}
75%{background-position:left 20px bottom 20px;}
100%{background-position:left 20px top 20px;}
}Run Code Online (Sandbox Code Playgroud)
<div class="b"></div>Run Code Online (Sandbox Code Playgroud)
It would be tedious to find the correct percentage or pixel values to place the 4 red squares like above, but by mixing both using calc() it is pretty easy.
Now, let's suppose we have something like this: calc(50% + 50px). How will the browser handle this?
In such case, the browser will first evaluate each unit to obtain the simplified form calc() then apply the above logic to position the image.
.b {
width:200px;
height:200px;
display:inline-block;
border:1px solid;
background-image:
linear-gradient(red,red),
linear-gradient(red,red),
linear-gradient(red,red),
linear-gradient(red,red);
background-size:20px 20px;
background-position:
calc(50% + 20px) 50%,
calc(50% - 20px) 50%,
50% calc(50% - 20px),
50% calc(50% + 20px);
background-repeat:no-repeat;
transition:0.5s;
}
.b:hover {
background-position:50%;
}Run Code Online (Sandbox Code Playgroud)
<div class="b"></div>
<div class="b" style="width:100px;height:100px;"></div>Run Code Online (Sandbox Code Playgroud)
calc(10% + 20px + 30% + -10px + 10% + 20px)
calc((10% + 30% + 10%) + (20px + -10px +20px))
calc(50% + 30px)
Run Code Online (Sandbox Code Playgroud)
Whatever the complexity of the formula is, the browser will always evaluate percentage and pixel values separately.
Besides calc(10% + 20px + 30% + -10px + 10% + 20px) unit we can also uses all the common units within background-position like calc(X% + Ypx), background-origin, content-box, padding-box, border-box etc. All will behave the same as pixel values.
.box {
display:inline-block;
width:200px;
height:200px;
background-image:url(https://picsum.photos/100/100?image=1069);
border:1px solid;
background-position:calc(10% + 20px + 30% + -10px + 10% + 20px) 0;
background-repeat:no-repeat;
}
.alt {
background-position:calc(50% + 30px) 0;
}
Run Code Online (Sandbox Code Playgroud)
<div class="box"></div>
<div class="box alt"></div>Run Code Online (Sandbox Code Playgroud)
So we can either use percentage values or length values (padding-box, left, top, etc)
Here is another important property that can be used to alter the position of background image. This property relies on the box model so lets get a quick reminder about how that works:
Each element has 3 different boxes inside it: border-box, padding-box and the content-box. transform specifies which box we need to consider in order to do all our previous logic.
Here is a self-explanatory example:
.b {
display:inline-block;
width:200px;
height:200px;
background:url(https://picsum.photos/100/100?image=1069) no-repeat;
border:20px solid rgba(0,0,0,0.1);
padding:20px;
box-sizing:border-box;
background-origin:border-box;
}
.p {
background-origin:padding-box; /*the default value*/
}
.c {
background-origin:content-box;
}Run Code Online (Sandbox Code Playgroud)
<div class="b"></div>
<div class="b p"></div>
<div class="b c"></div>Run Code Online (Sandbox Code Playgroud)
It should be clear now that when we don't have padding background-origin is equivalent to 100%, and when we don't have border 200% is equivalent to background-size.
1: Here is the full list of the equivalent values:
background-position = em = ch = exrem = cm = background-position = background-sizebackground-position = top = left = background-position30% 30% = 30% 30% = 30% 30% = 50% 50%100% 100%= 100% 0%=background-size
background-size = <gradient> =background-positionbackground-position= background-size =background-size0% = 100% =100%-50% 0= -50%=-50px