CSS - transform: scale() irrespective of element size - css

Is there a way to apply a transform: scale() to an element (or something similar, although ideally it should be able to be safely animated) which would make the element appear larger, however "ignore" the element's size (obviously this isn't exactly what I mean, keep reading).
Here is an example of what I mean.
Essentially the idea is to make the 2 differently size elements appear to scale in the same way, despite being 2 different sizes. It should be noted that the elements aren't going to be fixed width and will inherit the size of their container (whose width is also indeterminate).

Update
Thanks #TemaniAfif, the solution can be optimized further by manipulating the left and right margin instead of width.
.small {
width: 100px;
margin: 10px;
background-color: #1abc9c;
}
.large {
width: 900px;
margin: 10px;
background-color: #3498db;
}
.target {
background-color: inherit;
}
.target:hover {
margin: 0 -12px;
transform: scaleY(1.2);
transition: transform 0.3s ease-in-out, margin 0.3s ease-in-out;
}
<div class="small">
<div class="target">Small</div>
</div>
<div class="large">
<div class="target">Large</div>
</div>
Original Answer
The scale function resizes the element by multiplication, but you need a constant enlargement on the variant x-axis. Instead use scale, using calc on width of a proxy element (.target) to add the constant pixel when the element needs to be enlarged. By enlarging width, the position of the element also needs an offset to make it grows to left, so set the left to a negative number which is a half of the total enlargement. Since heights of the two elements are the same, using scaleY to scale them is ok.
.small {
width: 100px;
margin: 10px;
background-color: #1abc9c;
}
.large {
width: 900px;
margin: 10px;
background-color: #3498db;
}
.target {
position: relative;
left: 0;
width: 100%;
background-color: inherit;
}
.target:hover {
left: -12px;
width: calc(100% + 24px);
transform: scaleY(1.2);
transition: transform 0.3s ease-in-out, left 0.3s ease-in-out, width 0.3s ease-in-out;
}
<div class="small">
<div class="target">Small</div>
</div>
<div class="large">
<div class="target">Large</div>
</div>

Related

Percentage based max-height on transformed elements

I have a fixed position pop up window that I transform to center in the page.
This window is capable of increasing/decreasing in size as elements are added to it and I want to limit its growth to 75% of the window.
At the moment I define it's max-height using ems because, as I understand it, when an element is transformed it is taken out of flow and so no longer has a parent element to base percentages on.
Is there some pure css way I can make the max-height of this element based on the total window size even though I use transform?
Edit - add code example:
.fade-in-container {
text-align: left;
display: table;
max-height: 55em;
width: 40em;
transition: opacity 0.2s ease-in;
position: fixed;
height: 20em;
z-index: 12;
padding: 2em;
background: #F1F1F1;
border-radius: 1%;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
<body>
<footer></footer>
<div class='fade-in-container'></div>
</body>
use
#your-div {
max-height: 75vh;
}
Viewport Percentage Lengths
https://css-tricks.com/the-lengths-of-css/#article-header-id-12

Expand width of circle

I'm pretty new to CSS3 animations to I'd like to know you how to do the following one:
I have a circe:
On hover, I'd like to expand the width of the circle making it into a pill shape with a transition like in this image:
This is what I tried. The issue is that the circle transitions to an ellipse as the width expands :
.logo {
background: red;
width: 100px;
height: 100px;
border-radius: 50%;
transition: width 2s;
}
.logo:hover {
width: 300px;
}
<div class="logo"></div>
You just need to change the border-radius value to any other unit than percentage (all units listed here). For an explanation of how this works and why you need to use these units for the desired output, see Border-radius in percentage (%) vs pixels (px).
Example with px. The circle expands to a pill shape on hover :
.logo {
width: 100px;
height: 100px;
border-radius: 50px;
background: red;
transition: width 2s;
}
.logo:hover {
width: 300px;
}
<div class="logo"></div>
If you don't know the height of the circle, you can set a very high value so the circle keeps its pill shape as the width expands :
.logo {
width: 200px;
height: 200px;
border-radius: 999px;
background: red;
transition: width 2s;
}
.logo:hover {
width: 400px;
}
<div class="logo"></div>

Jagged "border" showing due to background colour on wrapper element with border-radius: 50%;

As I was in the process of trying to make an animated figure (transitions on hover), I found out that the background of my <figure> is showing near the edges when I apply border-radius: 50% to it, even though my image should be taking up all available space.
For a quick demo that illustrates the problem, please look at http://codepen.io/anon/pen/KwMMKz
HTML
<figure>
<img src="http://placehold.it/400x400" alt>
<figcaption>Demo</figcaption>
</figure>
CSS
figure {
background-color: red;
width: 400px;
height: 400px;
border-radius: 50%;
overflow: hidden;
position: relative; /* For caption */
}
img {
border-radius: 50%; /* Forced on image for smooth transition */
width: 100%;
transition: opacity 1s ease-out;
}
figcaption {
position: absolute;
top: 100%;
left: 0;
width: 100%;
color: hotpink;
text-align: center;
transition: top 1s ease-out;
}
figure:hover img {
opacity: 0;
}
figure:hover figcaption {
top: 50%;
}
Please note: I know that placing the background-color on figure:hover is a work-around, but I am more interested in the reason why this "jagged border"-like look is appearing.
My guess is that it has to do with AA rendering (or something related) of the browser and that it treats theĀ <figure> element differently than a media element such as <img>, but I can't find any proof of this online. Is this a bug, is it a "feature", or is it something I can actually fix?
Lastly, I also know that I could have used transform: translateY(); here for the animation, but that's not part of my question so please don't provide it as an answer.
UPDATE 17/12 14:03
It appears that this issue is not exclusive to border-radius: 50%. The issue can occur when any wrapping element uses border-radius in combination with overflow: hidden, when the wrapper contains content that is equal or bigger than the wrapper's dimensions.
UPDATE 17/12 14:14
Neither the usage of overflow: hidden on the wrapper element, nor the usage of border-radius on the contained image (or any other child element) seem to be the cause of this as they can be interchanged and the pixelated edge will still appear.
This seems to indicate that this issue is solely caused by 2 DOM elements being in exactly the same place, when any sort of border-radius is applied to the wrapper element and the visible area of the child is limited to that of the parent's.
I've been having same issue and ended up using pseudo element instead of background, kinda like that:
figure::before {
content: '';
display: block;
background-color: red;
width: 400px;
height: 400px;
transform: scale(0.997);
border-radius: 50%;
}
This allowed me to create 'pseudo background' which I later shrinked a little bit with transform: scale(0.997); so it will be just the same size but a bit below visible edge. Of course in your case you would also need to position image absolutely so it is not pushed below by this ::before.
It appears that it is indeed a "feature" of how the browser handles border-radius to give a smooth edge to the rounded corners of a container. The image background is anti-aliased in the same way (but as it is transparent has no effect) as can be seen by setting the img background color.
When the border is anti-aliased it "bleeds" into the background to soften the edges and so you are seeing that around the image as a "jaggy" ring in much the same way you would see a corona around the moon during a full solar eclipse.
the issue is always there, whether the anti-aliased object is covered or not, if you were to draw a circle then anti-alias it, you would see the circle is marginally narrower than the anti-aliased version. Most anti-aliasing algorithms aggregate the surrounding pixels of the object rather than those contained within it.
To overcome it, you'd either need to make your image large enough to cover the space taken up by the anti-aliased edge or reduce the container such that the anti-aliased area is smaller than the image.
You could add a new tag with an opacity of 0 then have that fade in with the image fading out.
figure {
width: 400px;
height: 400px;
border-radius: 50%;
overflow: hidden;
position: relative; /* For caption */
}
background {
background-color: red;
width: 400px;
height: 400px;
border-radius: 50%;
overflow: hidden;
opacity: 0;
position: fixed;
z-index: 5;
transition: opacity 1s ease-out;
}
img {
border-radius: 50%; /* Forced on image for smooth transition */
width: 100%;
transition: opacity 1s ease-out;
position: relative;
z-index: 100;
}
figcaption {
position: absolute;
top: 100%;
left: 0;
width: 100%;
color: hotpink;
text-align: center;
transition: top 1s ease-out;
z-index: 10000;
}
figure:hover img {
opacity: 0;
}
figure:hover background {
opacity: 1;
}
figure:hover figcaption {
top: 50%;
}
<figure>
<background></background>
<img src="http://placehold.it/400x400" alt>
<figcaption>Demo</figcaption>
</figure>
Notice I added the background tag and removed background-color from figure
http://codepen.io/marczking/pen/KwMgaR
So after playing around (used background-image and pseudo-elements, changes nothing...) you notice that this light border is only visible if you apply round corners. So I am assuming here it has to do how the Browser renders the CSS, nothing wrong with the CSS-rules ^^)
<figure>
<figcaption>Demo</figcaption>
</figure>
figure {
background-color: red;
width: 400px;
height: 400px;
border-radius: 100px;
position: relative; /* For caption */
}
figure::before {
content: "";
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
background: url("http://placehold.it/400x400") no-repeat;
border-radius: 100px; /* Forced on image for smooth transition */
transition: opacity 1s ease-out;
}
figcaption {
position: absolute;
top: 100%;
left: 0;
width: 100%;
color: hotpink;
text-align: center;
transition: top 1s ease-out;
}
figure:hover::before {
opacity: 0;
}
figure:hover figcaption {
top: 50%;
}

Transform scaleX relative to other elements

I want whenever I scale - adjacent elements to move accordingly. How can I do that? Whenever I do scale it goes on top of adjacent element.
jsbin
In opposite to that if I change width value it works as I wanted, yet I can't use width in transitions.
HTML:
<input>
<div class="foo">
CSS:
input{
display: inline-block;
transition: all 1s ease;
transform-origin:left;
}
input:focus{
transform: scaleX(2)
}
.foo{
display: inline-block;
width: 200px;
height: 20px;
background-color: red;
}
Remember to set both an initial and a destination value for your transitions, like so:
input{
display: inline-block;
vertical-align: top;
transition: width 1s ease;
transform-origin:left;
width: 100px;
}
input:focus{
width: 200px
}
JSBin illustrating this here

Animation stop with css3

At the moment i am working on a header with a slider animation (css3 only):
http://jimmytenbrink.nl/slider/
Everything is working fine except sometimes the slider is bugging if you go from the center to the right. It seems that i need to stop the animation for a few miliseconds to complete. However i searched everywhere on the internet but i cant seem to get it to work.
Anyone here has experience with it who can help me out?
HTML
<header>
<div><span>slide 1</span></div>
<div><span>slide 2</span></div>
<div><span>slide 3</span></div>
<div><span>slide 4</span></div>
<div><span>slide 5</span></div>
<div><span>slide 6</span></div>
<div><span>slide 7</span></div>
<div><span>slide 8</span></div>
</header>
CSS
header {
margin-top: 10px;
width: 800px;
overflow: hidden;
height: 500px;
}
header div {
background-color: #000;
width: 43.8px;
height: 200px;
position: relative;
float: left;
-webkit-transition: width .3s;
transition: width .3s;
overflow: hidden;
-webkit-animation-timing-function: linear;
-webkit-animation-iteration-count: 1;
-webkit-animation-fill-mode: forwards;
margin-right: 2px;
}
header div:first-child {
margin-left: 0px;
}
header div:last-child {
margin-right: 0px;
}
header div:hover span {
left: 50px;
opacity: 1;
}
header div img {
position: relative;
left: -240px;
-webkit-transition: all .3s;
transition: all .3s;
-webkit-filter: grayscale(1);
overflow:hidden;
}
header div span {
-webkit-transition: left .3s;
transition: left .3s;
position: absolute;
bottom: 30px;
color: white;
left: -350px;
opacity: 0;
width: 450px;
font-family:'Fugaz One', cursive;
text-transform: uppercase;
font-size: 24px;
color: #fff;
text-shadow: 0px 0px 10px #f1f1f1;
filter: dropshadow(color=#f1f1f1, offx=0, offy=0);
}
header:hover > div {
width: 43.8px;
}
header:hover > div:hover {
width: 150px;
}
Here is a JSFiddle
So the question is, how can i set a stop on the animation for a few miliseconds so the animation can finish before it gets triggered again?
Hope my question is clear!
(thanks for the edit)
One might call my answer a workaround. Maybe it is but according to my comment on ExtPro's answer - it is still completely pure CSS.
I decided to use display: table-cell since the table cell's width is distributed equally.
So, the CSS might look like this:
HINT: This is only a bunch of necessary CSS. All the code is in the jsFiddle
header {
width: 368px;
display: table;
overflow: hidden;
}
header > div {
width: 44px;
height: 200px;
position: relative;
-webkit-transition: width .3s;
transition: width .3s;
display: table-cell;
overflow: hidden;
}
header > div:hover {
width: 151px;
}
Fiddle
As you can see, we don't have to determine the width of all not-hovered divs. Actually, the problem came from that very CSS rule:
/* DON'T USE THIS RULE - IT'S THE RULE WHICH WAS BAD */
header:hover > div {
width: 43.8px;
}
You were changing the width of the divs on header:hover, so when the transition didn't manage to do its job in time, you came out with mouse pointing to the header but to non of the divs.
If I understand what you mean by 'bugging', what is happening is if you move the mouse quickly to the right, it traverses the currently open div and is left in an area which when that div collapses, does not contain (e.g. the mouse is not hovered over) the next one in order to expand it- namely the hover event of the following div(s) is/are not firing thus they do not expand. There wont be a CSS fix for this Im afraid as its browser related, you may want to replace with jQuery/JS.

Resources