How can I create a quadrilateral with css, when I know which degree each corner has.
I already tried to recreate a quadrilateral I have with transform and skew.
However, this does not work really well.
This is what I try to archive.
The exact requirements are:
A div with this as background in one color. On the image are just construction lines. It should be a solid quadrilateral with these angles.
This was my first idea:
transform: rotate(-45deg) skew(27.5deg, 62.5deg)
transform-origin: top center;
I would consider multiple background to achieve this where I simply need to find the width/height of the element. Based on your illustration we have this:
From this we can have the following formula:
tan(alpha) = W/H
and
tan(beta/2) = H/W
We only need to use one of them and you will notice that there isn't one solution which is logical as you simply need to keep a ratio between H and W and the width of our element will simply be 2*W and its height 2*H.
Since H/W is also the same as 2*H/2*W we can simply consider that width = tan(alpha)*height
.box {
height:var(--h);
width:calc(1.92098213 * var(--h)); /* tan(62.5)xH */
background:
linear-gradient(to bottom right,transparent 49%,red 50%) top left,
linear-gradient(to top right,transparent 49%,red 50%) bottom left,
linear-gradient(to bottom left ,transparent 49%,red 50%) top right,
linear-gradient(to top left ,transparent 49%,red 50%) bottom right;
background-size:50% 50%;
background-repeat:no-repeat;
}
<div class="box" style="--h:50px;"></div>
<div class="box" style="--h:100px;"></div>
<div class="box" style="--h:200px;"></div>
You can adjust the gradient if you want only borders:
.box {
height:var(--h);
width:calc(1.92098213 * var(--h)); /* tan(62.5)xH */
background:
linear-gradient(to bottom right,transparent 49%,red 50%,transparent calc(50% + 2px)) top left,
linear-gradient(to top right,transparent 49%,red 50%,transparent calc(50% + 2px)) bottom left,
linear-gradient(to bottom left ,transparent 49%,red 50%,transparent calc(50% + 2px)) top right,
linear-gradient(to top left ,transparent 49%,red 50%,transparent calc(50% + 2px)) bottom right;
background-size:50% 50%;
background-repeat:no-repeat;
}
<div class="box" style="--h:50px;"></div>
<div class="box" style="--h:100px;"></div>
<div class="box" style="--h:200px;"></div>
Using transform the idea is to rely on rotateX() in order to visually decrease the height to keep the formula defined previously. So we start by having Width=height (a square) then we rotate like below:
This is a view from the side. The green is our rotated element and the red the initial one. It's clear that we will see the height H1 after performing the rotation and we have this formula:
cos(angle) = H1/H
And we aleardy have tan(alpha)=W/H1 so we will have
cos(angle) = W/(H*tan(alpha))
and H=W since we defined a square initially so we will have cos(angle) = 1/tan(alpha) --> angle = cos-1(1/tan(alpha))
.box {
width:150px;
height:150px;
background:red;
margin:50px;
transform:rotateX(58.63017731deg) rotate(45deg); /* cos-1(0.52056)*/
}
<div class="box">
</div>
We can also apply the same logic using rotateY() to update the width in the situation where you will have beta bigger than 90deg and alpha smaller than 45deg. In this case we will have W < H and the rotateX() won't help us.
The math can easily confirm this. when alpha is smaller than 45deg tan(alpha) will be smaller than 1 thus 1/tan(alpha) will bigger than 1 and cos is only defined between [-1 1] so there is no angle we can use with rotateX()
Here is an animation to illustrate:
.box {
width:100px;
height:100px;
display:inline-block;
background:red;
margin:50px;
animation:change 5s linear infinite alternate;
}
.alt {
animation:change-alt 5s linear infinite alternate;
}
#keyframes change {
from{transform:rotateX(0) rotate(45deg)}
to{ transform:rotateX(90deg) rotate(45deg)}
}
#keyframes change-alt {
from{transform:rotateY(0) rotate(45deg)}
to{ transform:rotateY(90deg) rotate(45deg)}
}
<div class="box">
</div>
<div class="box alt">
</div>
In various way you can do it. Since you're trying to use degree value so here I can give you an example: first of you can take four lines for your rectangle and rotate them as you want with degree value. Here is what I mean:
<div class="top_line"></div>
<div class="right_line"></div>
<div class="bottom_line"></div>
<div class="left_line"></div>
Css
.top_line { height: 170px; border-right: 1px solid yellow; transform: rotate(50deg);
position: absolute; top: 140px; left: 400px; transform-origin: 0% 130%; }
.right_line {height: 140px; border-right: 1px solid red; transform: rotate(130deg);
position: absolute; top: 140px; left: 500px; transform-origin: 0% 50%; }
.bottom_line { height: 140px; border-right: 1px solid green; transform: rotate(130deg);
position: absolute; top: 140px; left: 400px; transform-origin: -1800% 80%; }
.left_line { height: 140px; border-right: 1px solid blue; transform: rotate(50deg);
position: absolute; top: 140px; left: 400px; }
Here is the live preview
Related
Is there any way to make background-position take percentage values? Currently my button only works with an explicit values for width and 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;
}
In Pixel
In Percentage
TL;DR
All the percentage values used with background-position are equivalent when using a gradient as background, so you won't see any difference. You need to specify a background-size different from the container 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;
}
Pixel
Percentage
How does background position work?
Let's use a classic image in order to explain how background-position works.
When using pixel values, the reference is the top/left corner of the image, whatever the size is. It's like using top/left with a positioned element:
.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;}}
<div class="b"></div>
When using percentage values, the reference is different from when you use pixel values; it's no longer the top/left corner:
.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 3s infinite linear alternate;
}
.b:before {
content:"";
position:absolute;
top:0;
left:0;
width:10px;
height:10px;
background:red;
animation:change 3s infinite linear alternate;
}
#keyframes back{to{background-position:100% 100%;}}
#keyframes change{to{top:200px; left:200px;}}
<div class="b"></div>
In this case, we need to consider two parameters: the size of the container AND the size of the image. Here is an illustration of how it works (I took a background-position equal to 30% 30%):
First, we consider the image to find the reference point we will use in order to place the image. It's the point inside the image that is positioned at 30% 30% from the top/left corner considering the size of the image (like defined with the green lines). Then, we place that point inside the container at 30% 30% from the top/left corner considering the size of the container.
From this logic, we can clearly identify some trivial cases like
50% 50% (center) 100% 100% (bottom right) 100% 0% (top right)
Now it's clear that if the size of the image is equal to the size of the container then nothing will happen simply because all the positions are equivalent. The top/left of the image is already at the top/left (0% 0%) of the container, the center is already at the center (50% 50%) etc.
.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%;}}
<div class="b"></div>
The above logic is the same when applied to gradients since gradients are considered images, and by default, if you don't specify a background-size, a gradient's size will be the size of its container, unlike when using an image.
If we refer to the specification of the background-size, we can see how your problem arises:
If both values are auto then the intrinsic width and/or height of the
image should be used, if any, the missing dimension (if any) behaving
as auto as described above. If the image has neither an intrinsic
width nor an intrinsic height, its size is determined as for contain.
And:
contain
Scale the image, while preserving its intrinsic aspect ratio
(if any), to the largest size such that both its width and its height
can fit inside the background positioning area.
And also:
A bitmap image (such as JPG) always has intrinsic dimensions and
proportions.
CSS <gradient>s have no intrinsic dimensions or intrinsic proportions.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.
More in-depth
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 no-repeat;
}
<div class="b"></div>
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;
}
<div class="b">
</div>
<div class="b a">
</div>
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}
}
<div class="b">
</div>
The same will logically happen for gradients:
.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}
}
<div class="b">
</div>
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:url(https://picsum.photos/100/100?image=1069) 150% 0/100px 100px no-repeat;
}
<div class="b"></div>
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/300/300?image=1069) 150% 0/50px 50px no-repeat;
animation:change 2s infinite linear alternate;
}
#keyframes change {
to {background-size:300px 300px}
}
<div class="b"></div>
Special cases
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:
p * Wp = p * Ws + Ws <=> p = Ws/(Wp - Ws) where p in [0,1]
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 Ws = Wp * s (s in [0,1] and S=s*100%), and the formula will be
p = Ws/(Wp - Ws) <=> p = s / (1 - s)
Adding the negative sign it will be p = s / (s - 1).
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 100%.
The new percentage p'% is 100% + p%, and the formula will be p' = 1 + p --> p' = 1 + s / (1 - s) = 1 / (1 - s).
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%)
}
}
<div class="b" style="--s:0.5">
</div>
<div class="b" style="--s:0.8">
</div>
<div class="b" style="--s:2">
</div>
Let's calculate some values:
When s=0.5, we have a background-size equal to 50%, and the percentage values will be from -100% to 200%. 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 (s=2) the background-size is equal to 200%, and the percentage values will be from 200% to -100%. 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).
Relation between pixel and percentage values
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 background-position:X Y
When using percentage values, we will consider the green lines and we will have background-position:Px Py.
The formula will be like follow : X + Px * Ws = Px * Wp where Ws is the width of the image and Wp is the width of the container (same formula for the Y axis considering height).
We will have X = Py * (Wp - Ws). From this formula we can validate two points as explained previously:
When Wp = Ws, 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.
X and Px will have the same sign when Wp > Ws and will have opposite sign when Wp < Ws. 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 background-size. We will have X = Px * Wp * (1-s).
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: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)));}
}
<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>
Changing the reference
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-position.
By default background-position: X Y is equivalent to background-position: left X top Y (position at X from the left and at Y from the top). By adjusting top and/or left we change the reference and how the image is placed. Here are some examples:
.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;
}
<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>
It's clear that for the X value we can only use left and right (the horizontal position) and with the Y value we can only use bottom and top (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: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
}
}
<div class="b" style="--s:0.5">
</div>
<div class="b" style="--s:0.8">
</div>
<div class="b" style="--s:2">
</div>
For s=0.5 we will no more animate from -100% to 200% BUT it will be from left -100% to right -100%.
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: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;}
}
<div class="b"></div>
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.
Combining pixel and percentage values
We can use calc() in order to do some complex calculation that involves different units. For example, we can write width:calc(100px + 20% + 12em) 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 background-position? If we write calc(50% + 50px), 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() and the logic is as follows:
We first use the percentage value to position the image by applying all the logic related to percentage values.
We consider the position of (1) as the reference and we use the pixel value to position the image again by applying all the logic related to pixel values.
So calc(50% + 50px) 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;
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%;
}
<div class="b"></div>
<div class="b" style="width:100px;height:100px;"></div>
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(10% + 20px + 30% + -10px + 10% + 20px). How will the browser handle this?
In such case, the browser will first evaluate each unit to obtain the simplified form calc(X% + Ypx) then apply the above logic to position the image.
calc(10% + 20px + 30% + -10px + 10% + 20px)
calc((10% + 30% + 10%) + (20px + -10px +20px))
calc(50% + 30px)
.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;
}
<div class="box"></div>
<div class="box alt"></div>
Whatever the complexity of the formula is, the browser will always evaluate percentage and pixel values separately.
Using background-origin
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. background-origin 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,
linear-gradient(to right,red,blue) bottom/100% 20% 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;
}
<div class="b"></div>
<div class="b p"></div>
<div class="b c"></div>
It should be clear now that when we don't have padding content-box is equivalent to padding-box, and when we don't have border border-box is equivalent to padding-box.
Make percentage behave differently
In case we really need to have the size of the image equal to the container size and move it using percentage like pixel we can consider the below ideas.
Using pseudo element as a background layer:
.b {
width:200px;
height:200px;
border:1px solid;
position:relative;
z-index:0;
overflow:hidden;
}
.b:before {
content:"";
position:absolute;
top:0;
left:0;
width:100%;
height:100%;
z-index:-1;
background:url(https://picsum.photos/200/200?image=1069);
background-size:100% 100%;
transition:1s;
}
.b:hover::before {
transform:translate(100%,100%);
}
<div class="b"></div>
We should note that translate consider the size of the pseudo element but since it's the same as the container we won't have any issue. We can also useleft/top but transform will have better performance.
Using background-origin
The trick is to have padding, restrict the origin to content-box and make the size bigger than 100% to cover the padding and have the image fill the container.
.b {
width:200px;
height:200px;
outline:1px solid;
padding:0 100px 100px 0;
box-sizing:border-box;
z-index:0;
overflow:hidden;
background:url(https://picsum.photos/200/200?image=1069) no-repeat;
background-origin:content-box;
background-size:200% 200%;
transition:0.8s;
}
.b:hover {
background-position:-200% -200%;
/* We use [0%,-200%] to cover [0%,100%]*/
}
<div class="b"></div>
In the above, I made the padding half the size so logically I need to use 200% in background-size to rectify. For the background-position, it's now easy to find the needed value based on the above explanation.
Another example:
.b {
width:200px;
height:200px;
outline:1px solid;
padding:50px;
box-sizing:border-box;
z-index:0;
overflow:hidden;
background:url(https://picsum.photos/200/200?image=1069) no-repeat;
background-origin:content-box;
background-size:200% 200%;
background-position:50% 50%;
transition:0.8s;
}
.b:hover {
background-position:-150% -150%;
/* We use [50%,-150%] to cover [0%,100%]*/
}
<div class="b"></div>
Note that other units like em, ch, etc, behave the same as px. They are called lengths.
Finally found the solution which doesn't use fixed measure or javascript
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;
transition: background 0.5s;
}
.button-percentage {
background-image: radial-gradient(circle at 50% 50%,#2484c6,#1995c8 51%,#00bbce);
background-repeat: repeat;
background-size: 200% auto;
background-position: 100% 0;
transition: background-position .5s ease-in-out
}
.button-percentage:hover {
background-position: 0 0;
}
In Percentage
good afternoon everyone, due to the css room being empty i come here to ask you for support in relation to the css, i'm trying to make a water drop effect, but so far i haven't been able to do that ... will it be possible to show me the right way? I already tested SVG shape element and Clip Path (Mask) CSS, but I couldn't get the format ... the idea would be to apply this effect to an image ...
evry time i implemente the css the image rotates:
https://ibb.co/J3sVQyn
this is the code i'm using css and react call:
.CardComponent-media-4 {
width: 145px;
height: 169px;
margin-top: 5px;
margin-bottom: 5px;
margin-left: 5px;
margin-right: 5px;
flex-basis: 20%;
z-index: 50;
border-radius: 50%;
border-top: 145/2 ;
border-left: 145/2;
border-bottom: 145/2;
border-left: 145/2;
border-top-right-radius: 0;
transform: rotate(45deg);
}
<CardMedia image={imageUrl} title={title} className={classes.media} />
You are almost good, simply make the image rotate in the opposite direction by considering another element:
.box {
width:150px;
height:150px;
position:relative;
border-radius:50% 0 50% 50%;
margin:50px;
transform:rotate(-45deg);
overflow:hidden;
}
.box:before {
content:"";
position:absolute;
top:-20%;
left:-20%;
right:-20%;
bottom:-20%;
background: center/cover;
background-image:inherit;
transform:rotate(45deg);
}
<div class="box" style="background-image:url(https://i.picsum.photos/id/1074/800/800.jpg)"></div>
Another idea using mask:
img {
width: 175px;
height: 200px;
-webkit-mask:
linear-gradient(to bottom right,transparent 48%,#fff 50%) 17% 0% /40% 40%,
linear-gradient(to bottom left ,transparent 48%,#fff 50%) 83% 0%/40% 40%,
radial-gradient(circle farthest-side at 50% 31%,#fff 90%,transparent 91%) bottom/100% 60%;
-webkit-mask-repeat:no-repeat;
mask:
linear-gradient(to bottom right,transparent 48%,#fff 50%) 17% 0% /40% 40%,
linear-gradient(to bottom left ,transparent 48%,#fff 50%) 83% 0%/40% 40%,
radial-gradient(circle farthest-side at 50% 31%,#fff 90%,transparent 91%) bottom/100% 60%;
mask-repeat:no-repeat;
}
<img src="https://i.picsum.photos/id/1074/800/914.jpg" >
Is there any way to make background-position take percentage values? Currently my button only works with an explicit values for width and 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;
}
In Pixel
In Percentage
TL;DR
All the percentage values used with background-position are equivalent when using a gradient as background, so you won't see any difference. You need to specify a background-size different from the container 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;
}
Pixel
Percentage
How does background position work?
Let's use a classic image in order to explain how background-position works.
When using pixel values, the reference is the top/left corner of the image, whatever the size is. It's like using top/left with a positioned element:
.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;}}
<div class="b"></div>
When using percentage values, the reference is different from when you use pixel values; it's no longer the top/left corner:
.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 3s infinite linear alternate;
}
.b:before {
content:"";
position:absolute;
top:0;
left:0;
width:10px;
height:10px;
background:red;
animation:change 3s infinite linear alternate;
}
#keyframes back{to{background-position:100% 100%;}}
#keyframes change{to{top:200px; left:200px;}}
<div class="b"></div>
In this case, we need to consider two parameters: the size of the container AND the size of the image. Here is an illustration of how it works (I took a background-position equal to 30% 30%):
First, we consider the image to find the reference point we will use in order to place the image. It's the point inside the image that is positioned at 30% 30% from the top/left corner considering the size of the image (like defined with the green lines). Then, we place that point inside the container at 30% 30% from the top/left corner considering the size of the container.
From this logic, we can clearly identify some trivial cases like
50% 50% (center) 100% 100% (bottom right) 100% 0% (top right)
Now it's clear that if the size of the image is equal to the size of the container then nothing will happen simply because all the positions are equivalent. The top/left of the image is already at the top/left (0% 0%) of the container, the center is already at the center (50% 50%) etc.
.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%;}}
<div class="b"></div>
The above logic is the same when applied to gradients since gradients are considered images, and by default, if you don't specify a background-size, a gradient's size will be the size of its container, unlike when using an image.
If we refer to the specification of the background-size, we can see how your problem arises:
If both values are auto then the intrinsic width and/or height of the
image should be used, if any, the missing dimension (if any) behaving
as auto as described above. If the image has neither an intrinsic
width nor an intrinsic height, its size is determined as for contain.
And:
contain
Scale the image, while preserving its intrinsic aspect ratio
(if any), to the largest size such that both its width and its height
can fit inside the background positioning area.
And also:
A bitmap image (such as JPG) always has intrinsic dimensions and
proportions.
CSS <gradient>s have no intrinsic dimensions or intrinsic proportions.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.
More in-depth
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 no-repeat;
}
<div class="b"></div>
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;
}
<div class="b">
</div>
<div class="b a">
</div>
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}
}
<div class="b">
</div>
The same will logically happen for gradients:
.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}
}
<div class="b">
</div>
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:url(https://picsum.photos/100/100?image=1069) 150% 0/100px 100px no-repeat;
}
<div class="b"></div>
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/300/300?image=1069) 150% 0/50px 50px no-repeat;
animation:change 2s infinite linear alternate;
}
#keyframes change {
to {background-size:300px 300px}
}
<div class="b"></div>
Special cases
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:
p * Wp = p * Ws + Ws <=> p = Ws/(Wp - Ws) where p in [0,1]
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 Ws = Wp * s (s in [0,1] and S=s*100%), and the formula will be
p = Ws/(Wp - Ws) <=> p = s / (1 - s)
Adding the negative sign it will be p = s / (s - 1).
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 100%.
The new percentage p'% is 100% + p%, and the formula will be p' = 1 + p --> p' = 1 + s / (1 - s) = 1 / (1 - s).
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%)
}
}
<div class="b" style="--s:0.5">
</div>
<div class="b" style="--s:0.8">
</div>
<div class="b" style="--s:2">
</div>
Let's calculate some values:
When s=0.5, we have a background-size equal to 50%, and the percentage values will be from -100% to 200%. 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 (s=2) the background-size is equal to 200%, and the percentage values will be from 200% to -100%. 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).
Relation between pixel and percentage values
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 background-position:X Y
When using percentage values, we will consider the green lines and we will have background-position:Px Py.
The formula will be like follow : X + Px * Ws = Px * Wp where Ws is the width of the image and Wp is the width of the container (same formula for the Y axis considering height).
We will have X = Py * (Wp - Ws). From this formula we can validate two points as explained previously:
When Wp = Ws, 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.
X and Px will have the same sign when Wp > Ws and will have opposite sign when Wp < Ws. 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 background-size. We will have X = Px * Wp * (1-s).
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: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)));}
}
<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>
Changing the reference
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-position.
By default background-position: X Y is equivalent to background-position: left X top Y (position at X from the left and at Y from the top). By adjusting top and/or left we change the reference and how the image is placed. Here are some examples:
.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;
}
<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>
It's clear that for the X value we can only use left and right (the horizontal position) and with the Y value we can only use bottom and top (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: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
}
}
<div class="b" style="--s:0.5">
</div>
<div class="b" style="--s:0.8">
</div>
<div class="b" style="--s:2">
</div>
For s=0.5 we will no more animate from -100% to 200% BUT it will be from left -100% to right -100%.
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: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;}
}
<div class="b"></div>
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.
Combining pixel and percentage values
We can use calc() in order to do some complex calculation that involves different units. For example, we can write width:calc(100px + 20% + 12em) 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 background-position? If we write calc(50% + 50px), 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() and the logic is as follows:
We first use the percentage value to position the image by applying all the logic related to percentage values.
We consider the position of (1) as the reference and we use the pixel value to position the image again by applying all the logic related to pixel values.
So calc(50% + 50px) 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;
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%;
}
<div class="b"></div>
<div class="b" style="width:100px;height:100px;"></div>
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(10% + 20px + 30% + -10px + 10% + 20px). How will the browser handle this?
In such case, the browser will first evaluate each unit to obtain the simplified form calc(X% + Ypx) then apply the above logic to position the image.
calc(10% + 20px + 30% + -10px + 10% + 20px)
calc((10% + 30% + 10%) + (20px + -10px +20px))
calc(50% + 30px)
.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;
}
<div class="box"></div>
<div class="box alt"></div>
Whatever the complexity of the formula is, the browser will always evaluate percentage and pixel values separately.
Using background-origin
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. background-origin 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,
linear-gradient(to right,red,blue) bottom/100% 20% 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;
}
<div class="b"></div>
<div class="b p"></div>
<div class="b c"></div>
It should be clear now that when we don't have padding content-box is equivalent to padding-box, and when we don't have border border-box is equivalent to padding-box.
Make percentage behave differently
In case we really need to have the size of the image equal to the container size and move it using percentage like pixel we can consider the below ideas.
Using pseudo element as a background layer:
.b {
width:200px;
height:200px;
border:1px solid;
position:relative;
z-index:0;
overflow:hidden;
}
.b:before {
content:"";
position:absolute;
top:0;
left:0;
width:100%;
height:100%;
z-index:-1;
background:url(https://picsum.photos/200/200?image=1069);
background-size:100% 100%;
transition:1s;
}
.b:hover::before {
transform:translate(100%,100%);
}
<div class="b"></div>
We should note that translate consider the size of the pseudo element but since it's the same as the container we won't have any issue. We can also useleft/top but transform will have better performance.
Using background-origin
The trick is to have padding, restrict the origin to content-box and make the size bigger than 100% to cover the padding and have the image fill the container.
.b {
width:200px;
height:200px;
outline:1px solid;
padding:0 100px 100px 0;
box-sizing:border-box;
z-index:0;
overflow:hidden;
background:url(https://picsum.photos/200/200?image=1069) no-repeat;
background-origin:content-box;
background-size:200% 200%;
transition:0.8s;
}
.b:hover {
background-position:-200% -200%;
/* We use [0%,-200%] to cover [0%,100%]*/
}
<div class="b"></div>
In the above, I made the padding half the size so logically I need to use 200% in background-size to rectify. For the background-position, it's now easy to find the needed value based on the above explanation.
Another example:
.b {
width:200px;
height:200px;
outline:1px solid;
padding:50px;
box-sizing:border-box;
z-index:0;
overflow:hidden;
background:url(https://picsum.photos/200/200?image=1069) no-repeat;
background-origin:content-box;
background-size:200% 200%;
background-position:50% 50%;
transition:0.8s;
}
.b:hover {
background-position:-150% -150%;
/* We use [50%,-150%] to cover [0%,100%]*/
}
<div class="b"></div>
Note that other units like em, ch, etc, behave the same as px. They are called lengths.
Finally found the solution which doesn't use fixed measure or javascript
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;
transition: background 0.5s;
}
.button-percentage {
background-image: radial-gradient(circle at 50% 50%,#2484c6,#1995c8 51%,#00bbce);
background-repeat: repeat;
background-size: 200% auto;
background-position: 100% 0;
transition: background-position .5s ease-in-out
}
.button-percentage:hover {
background-position: 0 0;
}
In Percentage
I want the bottom of my background-color to be another colour. I'm sure it involves a linear-gradient? but unsure on how to implement it
Sample code:
.background{
height:100px;
width:200px;
background-color: #11143b;
background: linear-gradient(top, red, red 70%, transparent 70%, transparent 100%);
}
<div class="background">
</div>
How I eventually want the above code to look:
Any help would be appreciated.
Simply like this:
.background{
height:100px;
width:200px;
background:
linear-gradient(to bottom right, transparent 49%,red 52%) bottom / 100% 20px no-repeat,
#11143b;
}
<div class="background">
</div>
Solution 1: After pseudo element
You can make a triangle an position it in the desired loscation. This element wont affect the content inside your element as it has a position of absolute
.background{
height:100px;
width:200px;
background-color: #11143b;
position: relative;
}
.background:after{
content: '';
position: absolute;
width: 0;
right: 0;
bottom: 0;
height: 0;
border-style: solid;
border-width: 0 0 10px 200px;
border-color: transparent transparent #ff0000 transparent;
}
<div class="background">
</div>
Solution 2: Gradient
This linear gradient can be a solution but might have some resolution problems
.background{
height:100px;
width:200px;
background-color: #11143b;
background: linear-gradient(0.48turn, #11143b 85%, red 75%);
}
<div class="background">
</div>
Hope this helps:>
Here is a jsbin of what I have so far and below is an image of what I am trying to construct:
Here is the html, I have only 2 sides of the pyramid added so far:
<div class="pyramid-container">
<div id="pyramid">
<div class="base"></div>
<div></div>
<div></div>
</div>
</div>
And here is the css:
.pyramid-container {
perspective: 800px;
}
#pyramid {
position: relative;
transform-style: preserve-3d;
transform-origin: 116px 200px 116px;
padding-left: 100px;
margin-top: 50px
}
#pyramid div:not(.base) {
position: absolute;
width: 0;
height: 0;
border-left: 100px solid transparent; /* left arrow slant */
border-right: 100px solid transparent; /* right arrow slant */
border-bottom: 100px solid; /* bottom, add background color here */
font-size: 12px;
line-height: 0;
opacity: .5;
}
.base {
position: absolute;
width: 200px;
height: 200px;
background-color: #ff0000;
transform: rotateX(80deg) translate3d(0px, 10px, 0px);
}
#pyramid div:nth-child(2) {
border-bottom-color: blue;//#e04545;
transform: rotateX(-30deg) rotateY(0deg) rotateZ(0deg) translate3d(0px, 0px, 100px);
}
#pyramid div:nth-child(3) {
border-bottom-color: yellow;//#ccaf5a;
transform: rotateX(30deg) rotateY(0deg) rotateZ(0deg) translate3d(0px, 25px, 0px);
}
I am using css3 to create 1 base rectangular div and 4 triangular divs.
I would like some help with the maths involved as well as how to position the elements.
I would like all 4 of the triangle sides to meet at an apex and have the four triangle bottom sides positioned on the rectangular div.
I am struggling with how to get the points of the different triangles to meet in at an apex.
Can anyone help me out with the maths or what logic to use to achieve this.
I'm not looking for code but more the logic or maths I should use.
So first, a couple fundamental points on CSS transforms
the order of transforms is important
the perspective will change with the size of container (#pyramid for you)
the origin of the transform is not inherited, and if not set with transform-origin, it is by default the center of the object (borders et al. included, afaict)
x is the horizontal axis, y the vertical one and z the one orthogonal to the screen's surface (when you don't have perspective)
Then on pyramids:
Let us look at the Base angle (let's call it α). Expressing the triangle sizes based on the angle α, you get:
width = Base
apothem (height of triangle) = (1/2 Base) / cos(α)
height of the pyramid = (1/2 Base) * tan(α)
In the pyramid of your attempt, Base = 200px thus 1/2 Base = 100px and Apothem = triangle height = 100px. This forces cos(α) = 1 thus α = 0° -- you will have a flat pyramid.
If you want α = 60°, you want apothem = 200px, and you'll get pyramid height = 173.2
If you want α = 45°, you want apothem = 141px, and you'll get pyramid height = 100
etc.
The main secret now you know the parameters, is to reason at each step, about where the axis are pointed, and at which point of the object you are applying the transforms. Paper & pencil or trial & error, whatever works is good.
So here's how I would do to place triangles:
put css-transform at the middle of the base of all triangles
rotate by a multiple of 90° around axis Y to orient each triangle for a different face of the pyramid (respectively 0, 90, 180, 270)
translate along Z by 1/2 Base to get the right position
rotate along X axis by the desired angle (90°-α) to make them meet at apex.
Thanks to the first rotation, the two identical last steps will do what you want on all triangles.
For the base, it's easier, you can keep the default css-transform
rotate by 90° along X (will make it "flat" on the plane perpendicular to the screen)
shift it along Z by (Apothem - 1/2 Base) to align with the base of the triangles
Below is what it would look like for α = 45°, feel free to not open the snippet if you don't want spoilers.
#pyramid {
perspective: 400px;
padding: 50px 0 0 200px;
}
#pyramid div:not(.base) {
position: absolute;
border-left: 100px solid transparent; /* 1/2 Base */
border-right: 100px solid transparent; /* 1/2 Base */
border-bottom: 141px solid; /* Apothem */
transform-origin: 100px 141px 0; /* bottom of trangle (1/2 Base, Apothem) */
opacity: .5;
}
.base {
position: absolute;
width: 200px;
height: 200px;
background-color: #2f2f2f;
/* transform by default from middle (100px, 100px)
move by Apothem - 1/2 Base = 41px */
transform: rotateX(90deg) translate3d(0px, 0px, -41px);
opacity: .5;
}
#pyramid div:nth-child(2) {
border-bottom-color: #e04545;
transform: rotateY(0deg) translate3d(0px, 0px, 100px) rotateX(45deg);
}
#pyramid div:nth-child(3) {
border-bottom-color: #ccaf5a;
transform: rotateY(90deg) translate3d(0px, 0px, 100px) rotateX(45deg);
}
#pyramid div:nth-child(4) {
transform: rotateY(180deg) translate3d(0px, 0px, 100px) rotateX(45deg);
}
#pyramid div:nth-child(5) {
border-bottom-color: #4ccfc7;
transform: rotateY(270deg) translate3d(0px, 0px, 100px) rotateX(45deg);
}
<!doctype html>
<html>
<head><title>Pyramid</title></head>
<body>
<div class="pyramid-container">
<div id="pyramid">
<div class="base"></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
</div>
</body>
</html>