CSS transform px sized div to 100vw/100vh - css

I have a div sized in pixels, and centered on screen with the top/left+transform trick. I've created a CSS animation to animate this box to fill the entire screen, but since it's based on height/width, the framerate is awful.
Here is a demo of what I've achieved. While the framerate is decent enough in the fiddle, in my actual use case with many other elements on the page, the framerate is terrible.
https://jsfiddle.net/ozxyfuje/
I want to convert this to use transform, but I'm not sure how to go about it, especially considering the transform that's already there to center it.
I tried to use calc() to figure out the scale factor from the dimensions of the div and the viewport, but apparently vw and vh are not compatible with calc().
Ideally I'd like to avoid JavaScript, but I can accept a JavaScript based solution as a last resort.

To avoid script you need to work with viewport units all the way, and then use scale()
Do note, to achive better perfomance don't use transition: all 0.5s, name which properties to be transitioned, like transition: transform 0.5s;
$("#hello").click(function(){
$("body").toggleClass("boom");
});
body {
background: #222;
/* full screen app */
width: 100%;
height: 100%;
overflow: hidden;
}
#hello {
background: #b00;
/* pixel size set in stone */
width: 40vw;
height: 40vh;
/* center on screen */
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
transition: transform 0.5s;
}
.boom #hello {
transform: translate(-50%, -50%) scale(2.5);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<div id="hello">
</div>
</body>

As far as I know it is not possible to achieve it using only CSS while maintaining a fixed width and height (not dependant on the width/height of the container).
You can achieve it using some JavaScript (jQuery in this case). I am adding the class 'full' to know if the element is full size or not, but you could achieve it with a boolean variable for example.
JSFiddle
$("#hello").click(function() {
if ($("#hello").hasClass('full')) {
$("#hello")
.removeClass('full')
.css({
"transform": "translate(-50%, -50%)"
});
} else {
$("#hello")
.addClass('full')
.css({
"transform": "translate(-50%, -50%) scale(" + $(window).width() / 200 + ", " + $(window).height() / 160 + ")"
});// 200 & 160 is the div width & height in pixels, set in the CSS
}
});
body {
background: #222;
/* full screen app */
width: 100%;
height: 100%;
overflow: hidden;
}
#hello {
background: #b00;
/* pixel size set in stone */
width: 200px;
height: 160px;
/* center on screen */
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
/* animation */
transition: 0.5s all;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="hello">
</div>

Related

Prevent off-screen div from moving on resizing

I have a drawer menu that appears on screen after clicking a button. The transition is a little laggy using absolute positioning so I went with using translate3d. The menu has two widths. One that's 100% of the view for mobile and 395px for viewports 600px and up. One quirk I'm noticing is that if I were to resize my screen, the menu will subtly appear. Is there a way to get the menu to completely stay off-screen when this happens?
Note: To see this, expand the snipped to full-screen and horizontally resize to 600px or lower. You should see see the div appear and go back off-screen.
$('button').on('click', function() {
$('#drawer').toggleClass('active');
});
html,
body {
height: 100%;
margin: 0;
}
#drawer {
width: 100%;
height: 100%;
background-color: grey;
transition: transform .5s ease-in;
transform: translate3d(-100%, 0, 0);
}
#drawer.active {
transform: translate3d(0, 0, 0);
}
#media (min-width: 600px) {
#drawer {
transform: translate3d(-395px, 0, 0);
width: 395px;
}
}
button {
position: absolute;
top: 10px;
left: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="drawer"></div>
<button>Toggle Drawer</button>
The problem: A transition is set on the drawer's transform property. When it hits the designated media query, the drawer transitions to it's new x coordinate.
The solution: Instead of putting the responsibility of placement solely on transform, use absolute positioning and initially offset the drawer to its' negative width. In this case it would be 395px. On the active state, the transform3d property would be the width of the drawer to bring it back into the visible part of the window.
$('button').on('click', function() {
$('#drawer').toggleClass('active');
});
html,
body {
height: 100%;
margin: 0;
}
#drawer {
width: 100%;
height: 100%;
position: absolute;
left: -100%;
background-color: grey;
transition: transform .5s ease-in;
transform: translate3d(0,0,0);
}
#drawer.active {
transform: translate3d(100%, 0, 0);
}
#media (min-width: 600px) {
#drawer {
left: -395px;
width: 395px;
}
#drawer.active {
transform: translate3d(395px, 0, 0);
}
}
button {
position: absolute;
top: 10px;
left: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="drawer"></div>
<button>Toggle Drawer</button>

CSS Border Image: rendering a frame by rotating an image

I need to render a frame (ie, a picture frame around a picture) by rotating an image:
0 degrees for the left
90 for the top
... and so on.
As far as I can tell there isn't a border-image-left|right|top|bottom property, although this would work too - please correct me if I'm wrong.
It seems I'll need to use the border-image property. Does anyone know if possible to rotate the image depending on the side?
I guess the other messy options would include
Creating four div's around the image
Manually generating a frame border image (this won't really work as 1. we've got over 300 images, and 2. the frames need to be used on images with different aspect ratios... )
Edit: 'depending on the side' = 0 degrees for left, 90 degrees for top, 180 degrees for right, 240 for bottom... See image below for an example.
Left hand border image
Partially forced, but wrapping it in a div and span and playing with pseudo elements and transforms seemed to work.
The image is wrapped in an .img-container div and a span, and the ::before and ::after elements are absolute positioned around the image.
Here's the markup:
<div class="img-container">
<span>
<img src="https://unsplash.it/300/300?image=200">
</span>
</div>
And the styling:
.img-container, span, img{
display: block;
position: relative;
}
/* Image border general */
.img-container::before,
.img-container::after,
span::before, span::after{
content: "";
position: absolute;
left: -30px;
top: 50%;
width: 30px;
height: 100%;
transform: translateY(-50%);
background-image: url("https://i.stack.imgur.com/0UI1w.png");
background-size: 100% 100%;
z-index: 2;
}
/* Specific to the right border */
.img-container::after{
left: auto;
right: -30px;
top: 50%;
transform: translateY(-50%) rotate(180deg);
}
/* Top and bottom border general */
span::before,
span::after{
top: 0;
left: 50%;
transform: translate(-50%, -50%) rotate(90deg);
}
/* Just the bottom */
span::after {
top: 100%;
left: 50%;
transform: translate(-50%, -50%) rotate(270deg);
}
May be a little much
Here's a fiddle

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

div not using available space (div:inline-block, position:fixed)

I've got a problem with a div whichis used as a overlay/"popup". I want it to use a max-width of 90% if needed. Unfortunately it always uses around 50% although theres more then enough text to fill the whole screen. But instead of using the width (too) it only stretches it vertically (which is fine). I am trying to avoid a absolute width-attribute because i want some kind of "width: auto;".
These are the relevant/applied styles (copied from the developer console):
element.style {
display: inline-block;
opacity: 1;
}
#media (min-device-width: 1000px) {
.Dialog_window {
max-height: 90%;
max-width: 90%;
width: auto;
-webkit-transform: translate(-50%, -50%);
-moz-transform: translate(-50%, -50%);
-ms-transition: translate(-50%, -50%);
-o-transition: translate(-50%,-50%);
transform: translate(-50%,-50%);
}
}
.Dialog_window {
background-color: #EEE;
padding: 20px;
border: 1px solid #FFF;
position: fixed;
overflow: auto;
z-index: 100000;
left: 50%;
top: 50%;
}
html {
font-size: 100%;
}
html {
font-family: sans-serif;
}
the Dom-Element is declared like this:
<div id="myID" class="Dialog_window" style="display: inline-block;"> [...] </div>
Thank you for any help in advance!
Regards
max-width and max-height tell the browser, "take up as much space as you need, but not any more than [x]". You're not forcing the element to occupy 90%, you're saying, "Not more than 90%". Unless you have enough content in the element to take up this space, this is the wrong property to style.
you may want to try using min-width and min-height, as these tell the browser, "starting at [x], take up this space".
since 90% of an absolutely positioned element is a lot of space, why not just stick with a fixed measurement, like width: 90%; max-height: 90%;?
.Dialog_window {
max-height: 90%;
width: 90%;
transform: translate(-50%,-50%);
}
If you need a flexible window, that sits within ranges, you should use both min-width and max-width:
.Dialog_window {
min-height: 50%;
max-height: 90%;
min-width: 50%;
max-width: 90%
transform: translate(-50%,-50%);
}

Translate X and Y percentage values based on elements height and width?

Translating an elements Y axis 50% will move it down 50% of its own height, not 50% of the parents height as I would expect. How do I tell a translating element to base it's translation percentage on the parent element? Or am I not understanding something?
http://jsfiddle.net/4wqEm/2/
When using percentage in a transform translate on a non-SVG element, it refers to the width or height of itself. Take a look at https://davidwalsh.name/css-vertical-center (demo):
One interesting thing about CSS transforms is that, when applying them with percentage values, they base that value on the dimensions of the element which they are being implemented on, as opposed to properties like top, right, bottom, left, margin, and padding, which only use the parent's dimensions (or in case of absolute positioning, which uses its closest relative parent).
On an SVG element, a transform percentage refers to the size of the parent instead!
Here is a pen:
https://codepen.io/trusktr/pen/gOdwWXv
svg, [outer] {
border: 1px solid black;
}
rect {
transform: translate3d(50%, 50%, 0);
}
[inner] {
background: black;
transform: translate3d(50%, 50%, 0);
}
<svg width="100" height="80">
<rect width="20" height="20" />
</svg>
<div outer style="width: 100px; height: 80px;">
<div inner style="width: 20px; height: 20px;"></div>
</div>
Strange, huh?
You can use vw and vh to translate based on the viewport size
#keyframes bubbleup {
0% {
transform: translateY(100vh);
}
100% {
transform: translateY(0vh);
}
}
What works for me using only CSS is:
.child {
position: relative;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
/* Backward compatibility */
-webkit-transform: translate(-50%, -50%);
-moz-transform: translate(-50%, -50%);
-o-transform: translate(-50%, -50%);
-ms-transform: translate(-50%, -50%);
}
How it works:
top and left positioning move child widget according to parent coordinates. Child widget's top-left corner will appear exactly in the center of parent (this is not what we want at this time).
translation will move child widget -50% to top and left based on its size (not the parent). It means, widget's center point will be moved exactly where top-left point was - which previously was set up as center of a parent, and this is what we want.
To use percentage in the translate property, you have to use Javascript : http://jsfiddle.net/4wqEm/27/
HTML code :
<div id="parent">
<div id="children"></div>
</div>​​​​​​​​​​​​​
CSS code :
#parent {
width: 200px;
height: 200px;
background: #ff0;
}
#children {
width: 10%;
height: 10%;
background: #f00;
}
Javascript code :
parent = document.getElementById('parent');
children = document.getElementById('children');
parent_height = parent.clientHeight;
​children_translate = parent_height * 50/100;
children.style.webkitTransform = "translateY("+children_translate+"px)";​​​​​​​​​​​​​​​​​​​​​​​​​​
I hope I could help you and say me if you have any other problem.
Your statement is absolutely right about the percentages coming from the very translated element. Instead of using translate property in your case you should be using absolute positioning to stay relative to the parent div. I absolutely positioned vertically your red div here:(don`t forget about adding position relative to the parent div.It has to be positioned other than static default):
js fiddle pen here
body {
margin: 0;
width: 100%;
height: 100%;
}
body > div {
width: 200px;
height: 200px;
background: #ff0;
position: relative;
}
body > div > div {
width: 10%;
height: 10%;
-webkit-transform: translateY(-50%);
background: #f00;
position: absolute;
top: 50%;
}
You can also use one extra block and use the transition for it except the child node
HTML code :
<div id="parent">
<div id="childrenWrapper">
<div id="children"></div>
</div>
</div>​​​​​​​​​​​​​
css should be something like this
#parent {
position: relative;
width: 200px;
height: 200px;
background: #ff0;
}
#childrenWrapper{
width: 100%;
height: 100%;
}
#children {
width: 10%;
height: 10%;
background: #f00;
}
You can make the element absolute positioned and use left and top property to take the percentage value as parent.
Its forked with positioning required on the following URL
working sample
body {
margin: 0;
width: 100%;
height: 100%;
}
body>div {
position: relative;
width: 200px;
height: 200px;
background: #ff0;
}
body>div>div {
position: absolute;
left: 50%;
top: 50%;
width: 10%;
height: 10%;
background: #f00;
transform: translate(-50%, -50%);
}
notes :
you can absolute positioning of your red square by changing parent element to position relative
then using 50% top and 50% left will position red square according to its upper left corner
using transform:translate(-50%,-50%) will position red square according to its center
The solution to this problem is not to use translate at all. When you are translating an element, the percentage you select is based on it's own height.
If you want to position the element based on the parent's height, use top: 50%;
So the code will look like this:
body {
margin: 0;
width: 100%;
height: 100%;
}
body > div {
width: 200px;
height: 200px;
background: #ff0;
position: relative;
}
body > div > div {
position: absolute;
top: 50%;
width: 10%;
height: 10%;
/* -webkit-transform: translateY(50%); */
background: #f00;
}

Resources