transform-origins y-offset position when using calc() - css

In this demo below, I am using transform-origin like this:
transform-origin: 50% calc(100% + 6em);
The y-offset value is set at calc(100% + 6em), but what am I setting the value of the y-offset to? I can see that it is + 6em, but + 6em from where, exactly?
.container {
width: 400px;
height: 400px;
background: red;
margin: 0 auto;
cursor: pointer;
}
.me {
position: relative;
width: 200px;
height: 200px;
border: 2px solid #444;
background: pink;
margin: 20% auto;
transition: 2s;
transform: rotateZ(45deg);
transform-origin: 50% calc(100% + 6em);
cursor: pointer;
}
.container:hover .me {
transform: rotateZ(0deg);
}
<div class="container">
<div class="me"></div>
</div>

When the transform-origin is given two values, like in your example, it is setting the x-offset and the y-offset, using the "two-value syntax":
transform-origin: x-offset y-offset
The percentage value length is based on the element that the transform origin is set on.
The x-offset begins at the left of the element. 50% plots the x-offset position in the very middle of the element.
The y-offset begins at the top of the element. 100% + 6em plots the y-offset position at the bottom of the element plus an extra 6 em.
The x and y offset meet to form a single point, illustrated here where the two orange lines meet:
Offset position — live example
In this example, the position of the offset is shown with the two pseudo elements.
You can change the two values of the before and after pseudo elements at the bottom of the CSS to easily show where the offset point location is. Change the values as shown in the CSS comments to plot the point visually.
.container {
width: 400px;
height: 400px;
background: #000;
margin: 0 auto;
cursor: pointer;
position: relative;
margin-top: 100px;
}
.container:after {
content: '';
display: block;
height: 200px;
width: 200px;
position: absolute;
top: 0;
left: 0;
background: rgba(255, 255, 255, 0.5);
}
.me {
position: relative;
width: 200px;
height: 200px;
background: pink;
transition: 2s;
transform: rotateZ(45deg);
cursor: pointer;
}
.me:before {
content: '';
display: block;
height: 5px;
position: absolute;
margin-top: -5px;
left: 0;
background: #F90;
}
.me:after {
content: '';
display: block;
width: 5px;
position: absolute;
top: 0;
margin-left: -5px;
background: #F90;
}
.container:hover .me {
transform: rotateZ(0deg);
}
.me {
/* x-offset | y-offset */
transform-origin: 50% calc(100% + 6em);
}
.me:after {
height: calc(100% + 6em); /* Set to y-offset value */
left: 50%; /* Set to x-offset value */
}
.me:before {
width: 50%; /* Set to x-offset value */
top: calc(100% + 6em); /* Set to y-offset value */
}
<div class="container">
<div class="me"></div>
</div>

Related

css top tilted skew with background-image

enter image description here
I want to make a similar effect to this one not changing html code , using only CSS , In HTML i have got only one div with class "square" , Thank you for your support in advance .
i think that is what you want
.container {
font-size: 16px;
background: #fff;
margin: 0 auto;
-webkit-transform-style: preserve-3d;
-moz-transform-style: preserve-3d;
transform-style: preserve-3d;
-webkit-perspective: 28em;
-moz-perspective: 28em;
perspective: 28em;
position: relative;
top: 100px;
}
.box {
position: absolute;
width: 14em;
height: 14em;
left: 50%;
margin-left: -7em;
backface-visibility: hidden;
}
.anim {
transition: all 0.5s ease-in-out;
}
.b0 {
transform: translateX(-11.7em) rotateY(30deg) ;
}
.box img {
width: 100%;
height: 100%;
border-radius: 5px;
}
#media(max-width: 768px) {
.container {
font-size: 12px;
}
}
#media(max-width: 560px) {
.container {
font-size: 8px;
}
}
<div class="container">
<div class="box anim b0">
<img src="http://www.skitzone.com/wp-content/uploads/2010/06/I_am_nothing__in_the_dark_by_islandtime-630x630-500x500.jpg" alt="" />
</div>
</div>
The requirement is to cut the top in a sloping manner.
This snippet does this by putting the linear-gradient that is required for the border into a before pseudo element, using clip-path to get the required cutting off of the top, and putting the image as background on an after pseudo element.
.square {
width: 20vmin;
height: 20vmin;
clip-path: polygon(0 0, 100% 20%, 100% 100%, 0 100%);
position: relative;
}
.square::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(red, blue);
background-image: linear-gradient(to right, #a2ca3c 0%, #0a7cff 50%, #a2ca3c 100%);
z-index: -1;
}
.square::after {
content: '';
position: absolute;
--borderW: 3%;
top: var(--borderW);
left: var(--borderW);
width: calc(100% - (2 * var(--borderW)));
height: calc(100% - (2 * var(--borderW)));
background-image: url(https://pesi.pl/img/main-bg.jpg);
background-size: cover;
background-position: center center;
background-repeat: no-repeat no-repeat;
clip-path: polygon(var(--borderW) var(--borderW), calc(100% - var(--borderW)) calc(20% + var(--borderW)), calc(100% - var(--borderW)) calc(100% - var(--borderW)), var(--borderW) calc(100% - var(--borderW)));
z-index: -1;
}
<div class="square"></div>
Obviously you will want to decide on exactly what width you want the border to be and whether the border is included in the overall size of the .square element (as here).

::before and ::after elements overlapping each other ruining the background transparancy

I have a simple div element that I wanna apply a background shape to it when the user hovers over it by using the ::before and ::after pseudo elements. I rotated these elements with rotateX(). How can I style it that the elements shouldn't overlap each other (or at least not ruin the background color) but it should look like a single shape?
Tried using % but didn't work.
Please help.
Thanks so much 🙏
div{
width:200px;
padding: 18px;
margin: 10px auto;
/* border: 1px solid black; */
text-align:center;
position: relative;
perspective: 100px;
z-index: 1;
}
div:hover{
color:#fff;
}
div:hover::before, div:hover::after{
content: "";
display: block;
background-color: #00000050;
width: 100%;
height: 50px;
position: absolute;
left: 0%;
z-index: -1;
}
div::before{
top:0;
transform: rotateX(-75deg);
}
div::after{
bottom:0;
transform: rotateX(75deg);
}
<div>Hello World</div>
If you make half of each pseudo element only have the color then when you rotate them the colors don't overlap.
A minor adjustment to the padding of the div was needed to get the two rotated 'halves' to meet correctly so this would have to be looked at if you ever went for a responsive rather than a fixed px unit solution.
This snippet removes the background-color from the pseudo elements, instead using a linear-gradient background-image going just half way up (or down) the pseudo element.
div {
width: 200px;
padding: 18px;
padding: 16px;
margin: 10px auto;
/* border: 1px solid black; */
text-align: center;
position: relative;
perspective: 100px;
z-index: 1;
}
div:hover {
color: #fff;
}
div:hover::before,
div:hover::after {
content: "";
display: block;
margin: 0;
padding: 0;
width: 100%;
height: 50px;
position: absolute;
left: 0%;
z-index: -1;
}
div::before {
top: 0;
transform: rotateX(-75deg);
background-image: linear-gradient(#00000050 0 50%, transparent 50% 100%);
}
div:hover::after {
bottom: 0;
transform: rotateX(75deg);
background-color: transparent;
background-image: linear-gradient(to top, #00000050 0 50%, transparent 50% 100%);
}
<div>Hello World</div>
A Haworth's answer covers using linear gradient stops to hide the color of half of each pseudo element.
Another approach you could take is to use only one of the pseudo elements with a polygon clip path to make your shape.
.container { display: flex; }
.hoverable { position: relative; margin: auto; padding: 10px 100px; }
.hoverable:hover::before {
content: "";
position: absolute;
inset: 0;
/* top: 0; left: 0; right: 0; bottom: 0; */
background-color: rgba(0, 0, 0, 0.25);
clip-path: polygon(0 0, 100% 0, 80% 50%, 100% 100%, 0 100%, 20% 50%);
}
<div class="container">
<div class="hoverable">Hello, World!</div>
</div>

Smooth CSS Transform Scale on rectangle, keeping an even border

I have an absolutely positioned div that I want to have slowly increase in size (5s transition) on hover, to become a "border" for a relative-positioned div on top of it:
<div class="rectangle">
<div class="background"></div>
<div class="content">blah</div>
</div>
Styles (vendor prefixes removed for readability):
.rectangle {
position: relative;
}
.background {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.content {
height: 800px;
width: 200px;
}
Transitioning the overall .background size results in choppy animation but an even border:
.rectangle:hover .background {
width: calc(100% + 40px);
height: calc(100% + 40px);
top: -20px;
left: -20px;
right: -20px;
bottom: -20px;
transition: 5s linear all;
}
Transitioning a border is choppy animation, but (obviously) an even border
.rectangle:hover .content {
border: 20px solid red;
transition: 5s linear all;
}
Transitioning a transform-scale is smooth, but results in a larger top and bottom "border" because it is a rectangle:
.rectangle:hover .background {
transition: 5s transform;
transform: scale(1.1);
}
Any way to either get transform-scale to keep even dimensions, or any other way to create this effect?
You can try using box shadow as a border to achieve smooth transitions.
.rectangle {
position: relative;
width: 300px;
height: 300px;
top: 100px;
left: 30%;
}
.background {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.background::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
box-shadow: 0 0 0 0px #000;
transition: 5s linear box-shadow;
}
.content {
height: 300px;
width: 200px;
}
.rectangle:hover .background::before {
box-shadow: 0 0 0 20px #000;
transition: 5s linear box-shadow;
}
<div class="rectangle">
<div class="background"></div>
<div class="content">blah</div>
</div>

Span position absolute is not centered with top and left

I want to create a "X" with css spans and position absolute, but the spans aren't centered even if they should.
The container has the font-size of 1px. and a height and width of 100em. Therefore I can use 1em as 1% of the parents size.
I used transform-origin: 0px 5em; on the span, to rotate it without changing the starting point. The Element starts in 20% top and left (20em) and ends in 80% (top and left).
To get the required width i simply calculated: Square root( square of (60) * 2) (Pythagorean theorem) (60 because start and end 20 -- 100-20*2)
But for some reason the X is clearly not centered. Do you know what i did wrong?
body
{
margin: 0px;
}
.check
{
font-size: 1px;
position: relative;
height: 100em;
width: 100em;
background-color: white;
border-radius: 50%;
transition: .3s;
box-shadow: 0px 0px 10px red inset;
}
.check span
{
position: absolute;
display: block;
height: 10em;
width: 0px;
background-color: #00FF00;
transition:.3s;
}
.check.red span
{
background-color: #FF0000;
transform-origin: 0px 5em;
transform: rotate(45deg);
top: 20em;
left: 20em;
}
.check.red span:nth-of-type(2)
{
transform: rotate(135deg);
top: 20em;
left: 80em;
}
.check.red:hover span
{
width: 84.852813742em;
}
<body>
<div class="check red">
<span></span>
<span></span>
</div>
</body>
This isn't an automatic solution, but changing some values in your css i solved it:
body
{
margin: 0px;
}
.check
{
font-size: 1px;
position: relative;
height: 100em;
width: 100em;
background-color: white;
border-radius: 50%;
transition: .3s;
box-shadow: 0px 0px 10px red inset;
}
.check span
{
position: absolute;
display: block;
height: 10em;
width: 0px;
background-color: #00FF00;
transition:.3s;
}
.check.red span
{
background-color: #FF0000;
transform-origin: 0px 5em;
transform: rotate(45deg);
top: 18em;
left: 22em;
}
.check.red span:nth-of-type(2)
{
transform: rotate(135deg);
top: 18em;
left: 78em;
}
.check.red:hover span
{
width: 78em;
}
<body>
<div class="check red">
<span></span>
<span></span>
</div>
</body>
There are a few things you can do to make life easier here.
Firstly you can transform origin using a percentage, which means you don't need to calculate it yourself.
You can also position using a percentage, then offset using a transform (again with a percentage) to center no matter the size.
You can also set the width of the cross using a percentage, which will take it size from its parent.
Update:
Change the cross to animate from the top, rather than the center by using background gradients.
.check
{
position: relative;
height: 200px;
width: 200px;
background-color: white;
border-radius: 50%;
box-shadow: 0px 0px 10px red inset;
}
.check span
{
position: absolute;
display: block;
height: 20px;
width: 0%;
background: linear-gradient(to right, white 50%, red 50%);
background-size: 200% 100%;
background-position: left bottom;
top: 50%;
left: 50%;
transform-origin: center;
transition: background 0.3s ease;
}
.check.red span
{
transform: translate(-50%, -50%) rotate(-45deg);
}
.check.red span:last-child
{
transform: translate(-50%, -50%) rotate(-135deg);
}
.check.red:hover span
{
background-position: right bottom;
width: 70%;
}
<div class="check red">
<span></span>
<span></span>
</div>
Try this
use margin-top:-0.5rem;
.check span
{
position: absolute;
display: block;
height: 10em;
width: 0px;
background-color: #00FF00;
transition:.3s; margin-top:-0.5rem;
}
body
{
margin: 0px;
}
.check
{
font-size: 1px;
position: relative;
height: 100em;
width: 100em;
background-color: white;
border-radius: 50%;
transition: .3s;
box-shadow: 0px 0px 10px red inset;
}
.check span
{
position: absolute;
display: block;
height: 10em;
width: 0px;
background-color: #00FF00;
transition:.3s; margin-top:-0.5rem;
}
.check.red span
{
background-color: #FF0000;
transform-origin: 0px 5em;
transform: rotate(45deg);
top: 20em;
left: 20em;
}
.check.red span:nth-of-type(2)
{
transform: rotate(135deg);
top: 20em;
left: 80em;
}
.check.red:hover span
{
width: 84.852813742em;
}
<body>
<div class="check red">
<span></span>
<span></span>
</div>
</body>

partially filling svg/png with color using css

I am new in CSS HTML. I am trying to following thing with CSS. I have a png icon. Now I want to partially fill-up it with color from bottom to top like the link of the image.
Are you trying to achieve something like this?
I inserted a div (represents the filling) into your pin and set the position property to absolute. Further I changed the position property of the parent div which represents the pin to relative, now you can align your filling absolute but within its parent.
body,
html {
height :100%;
}
body {
background: #2F2F2F;
}
.pin {
width:30px;
height: 30px;
border-radius: 50% 50% 50% 0;
background: black;
position: relative;
transform: rotate(-45deg);
left: 50%;
top: 50%;
margin: -20px 0 0 -20px;
}
.pin-fill {
width :10px;
height: 10px;
background: yellow;
position: absolute;
border-radius: 50% 50% 50% 0;
transform: rotate(1 deg);
left: 0;
bottom: 0;
}
<div class='pin'>
<div class="pin-fill"></div>
</div>
EDIT
If you want your inner pin (.pin-fill) look like a filling, I would suggest to change your it's border-radius as following.
border-radius: 0 100% 0 0;
Snippet
body,
html {
height :100%;
}
body {
background: #2F2F2F;
}
.pin {
width:30px;
height: 30px;
border-radius: 50% 50% 50% 0;
background: black;
position: relative;
transform: rotate(-45deg);
left: 50%;
top: 50%;
margin: -20px 0 0 -20px;
}
.pin-fill {
width :10px;
height: 10px;
background: yellow;
position: absolute;
border-radius: 0 100% 0 0;
transform: rotate(1 deg);
left: 0;
bottom: 0;
}
<div class='pin'>
<div class="pin-fill"></div>
</div>
Here is an example with plain filling
body,
html {
height: 100%;
}
body {
background: #2F2F2F;
}
.pin {
width: 30px;
height: 30px;
border-radius: 50% 50% 50% 0;
background: black;
position: relative;
transform: rotate(-45deg);
left: 50%;
top: 50%;
margin: -20px 0 0 -20px;
}
.pin-fill {
width: 0;
height: 0;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-top: 10px solid yellow;
position: absolute;
left: -5px;
bottom: 0px;
transform: rotate(45deg);
}
<div class='pin'>
<div class="pin-fill"></div>
</div>

Resources