I have an element that scales using transform when hovered over. This is great but scaling it on a static number isn't very useful if I want the website to be viewable on a variety of browser/screen sizes. The code looks like this right now:
<!DOCTYPE html>
<html>
<head>
<script>
{
const w = window.innerWidth/200;
const h = window.innerHeight/200;
}
</script>
<style>
.botright
{
width: 100px;
height: 100px;
top: 50%;
left: 50%;
position: absolute;
background: pink;
transition: transform 500ms ease-in-out;
transform-origin: left top;
display: flex;
align-items: center;
justify-content: center;
font-family: sans-serif;
}
.botright:hover
{
transform: scaleX(w) scaleY(h);
font-size: 0;
}
The notable bits are at the top and bottom of the code (the js and the :hover). I'm unable to use the w or h constants created in the javascript anywhere else in the css and the js doesn't work inside or encompassing the :hover so I'm sort of at a loss on how to make the element expand to a size relative to the length and width of the view window.
A static number in the scale() would work if the element itself was scaled to the window size instead but that resulted in some other problems and more importantly, isn't what I'm looking to do.
The current functional version does use a simple number to scale the element by but because the element is always 100px x 100px (and I am intentionally using pixels because I always want the element to be a square when not hovered over no matter what), scaling just makes a bigger square.
I am looking for a way to scale the square so that when hovered over, it will always go exactly to the very edge of the available window space.
I think you can do it like this:
.box {
background: #05273D;
border-radius: 5px;
height: 100px;
width: 100px;
margin: 100px;
transition: transform 1s;
}
.box:hover {
transform: scale(2);
}
<div class='box'></div>
You can learn more from here: https://www.w3schools.com/css/css3_2dtransforms.asp
You cannot pass Javascript variables to a style tag like this. A solution would be to create the style tag with javascript and concatenate the calculated values.
<script>
const w = window.innerWidth/200;
const h = window.innerHeight/200;
var styleTag = document.createElement("style");
styleTag.innerHTML = '.botright:hover { transform: scaleX(' + w + ') scaleY(' + h + '); font-size: 0; }';
document.head.appendChild(styleTag);
</script>
<style>
.botright
{
width: 100px;
height: 100px;
top: 50%;
left: 50%;
position: absolute;
background: pink;
transition: transform 500ms ease-in-out;
transform-origin: left top;
display: flex;
align-items: center;
justify-content: center;
font-family: sans-serif;
}
</style>
<div class="botright">TEST</div>
However note that this will not be updated on window's resize. If you need so, you can put the js code in a function that you bind to window resize event. However if you so, your function should give an id to the style tag, and remove it if it exists before adding it again.
Related
TL;DR: How to keep the div children proportional to the div itself?
I have a div, containing various elements like text, images, icons etc. It keeps 16:9 aspect ratio and fills as much viewport it can, while resizing the browser window, the div (with background different from the body background) changes size well, though the contents are staying the same size which is bad because I'm trying to make a presentation website which needs to look the same at various resolutions. How do I make the child elements align and resize properly inside the div?
I tried using viewport units though it didn't turn out really well.
My Code:
I tried using % units to set font size and then use em to scale other things but it didn't work. I also tried using only % units to set all properties but it did not work either
body {
background: black;
user-select: none;
margin: 0;
height: 100vh;
}
.container2 {
overflow: auto;
box-sizing: border-box;
resize: both;
overflow: auto;
max-width: 100%;
height: 100%;
display: flex;
justify-content: center;
}
.presentation-place {
user-select: none;
background: white;
top: 50%;
transform: translate(0, -50%);
position: absolute;
align-items: center;
aspect-ratio: 16 / 9;
}
#media screen and (max-aspect-ratio: 16 / 9) {
.presentation-place {
width: 100vw;
}
}
#media screen and (min-aspect-ratio: 16 / 9) {
.presentation-place {
height: 100vh;
}
}
.slide {
font-size: 100%;
position: absolute;
top: 0;
bottom: 0;
margin: 0 auto;
width: 100%;
height: 100%;
overflow: hidden;
background: red;
background-position: center center;
}
.title1 {
margin-left: 1em;
font-size: 6em;
position: absolute;
margin-top: 2em;
}
<html>
<body>
<div class="container">
<div class="presentation-place">
<div class="slide s1">
<h1 class="title1">test</h1>
</div>
</div>
</div>
</body>
</html>
Make sure to avoid specific units like cm, px etc because those are fixed units no matter the scale of the site itself or the monitor, the use of Units like % since vh/vw didnt work. % scales relative to the size of the monitor or website, so this should help. Alternativly you could use aspect-ratio because it scales relative to the size of the parent element
I would like to get a circle to expand from itself, while keeping the original circle. What I want is something like when you hover over the circles (e.g. water) on this page (click lets get started to see the circles). I'm not sure how to do this. Note that my knowledge of jQuery is quite small, so if you find a way to do this with jQuery, can you try to keep it simple? Thanks in advance. The earlier the better, as this is for a school project.
I tried to make the div have a function for onmouseover, but then I don't know how to get the rest. I was thinking about while the div animates from a smaller width and height, to move the circle, but the circle will still expand from the middle, and not the old circle.
Start with a CSS-only setup, then see if you actually need Javascript at all. This will generally always be more responsive/faster-loading. However, if you're already loading a JS library and it has functions built for this (like jQuery), then sure make use of them. There are plenty of tutorials for animating elements, CSS or JS.
Play around with numbers and styling as you wish.
Codepen
#container {
width: 100%;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.circle {
width: 200px;
height: 200px;
background-color: red;
border-radius: 50%;
}
.circle:before {
content: "";
width: 200px;
height: 200px;
border-radius: 50%;
position: absolute;
z-index: -1;
display: inline-block;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
transition: 0.5s ease-in-out;
}
.circle:hover:before {
transform: scale(1.7) translate(-20%,-30%);
background-color: pink;
}
<div id="container">
<div class="circle red"> </div>
</div>
With the following CSS, I am preparing my segment message to slide across the viewport:
.Segment {
position: absolute;
width: 100%;
overflow: hidden;
top: -5px;
top: 0;
outline: 1px solid orange;
}
.Segment__message {
display: inline-block;
margin-top: 15px;
left: 100%;
transform: translateX(0);
position: relative;
padding-left: 10px;
will-change: transform;
font-size: 30px;
}
If I apply the following styles dynamically, I am getting some very slight jank:
var message = document.querySelector(".Segment__message");
message.style = "transition: all 20s linear; transform: translateX(calc(-100vw - 100%))"
It is pretty subtle, but is much more noticeable on the 75" screen this will be displayed on.
Using Chrome's perf tools, I can see some FPS degradation, with it dropping to 8 FPS at one point. Is there anything I can do to smooth this out further?
https://codepen.io/anon/pen/OrOvdP
I removed the position property from the .Segment__message, and positioned it using only transform.
I've also used translate3d, which forces hardware acceleration and has improved animation performance for me in the past.
I don't see jank in Firefox, Chrome, or Safari with the code below.
var link = document.querySelector(".slide");
var message = document.querySelector(".Segment__message");
var styleStr = `transition: all 10s linear; transform: translate3d(-100%, 0, 0)`;
link.onclick = () => {
message.style = styleStr;
}
.Segment {
position: absolute;
width: 100%;
overflow: hidden;
top: 0;
outline: 1px solid orange;
}
.Segment__message {
display: inline-block;
margin-top: 15px;
transform: translate3d(100vw, 0, 0);
padding-left: 10px;
will-change: transform;
font-size: 30px;
}
.Segment__message::after {
content: "/";
color: blue;
display: block;
float: right;
padding-left: 15px;
}
.slide {
display: block;
margin-top: 50px;
}
<div class="Segment">
<div class="Segment__message">I am a message</div>
</div>
<a class="slide" href="#">Slide left</a>
You could do some enhancements to make sure your message will be drawn on a new, separate layer, like:
.Segment {
// ...
perspective: 600px;
z-index:2;
}
.Segment__message {
// ...
z-index:3;
will-change: transform;
transform-style: preserve-3d;
font-size: 30px;
}
But there is one little nasty trick that you can do along with will-change property, if you will apply some really small delay (like 0.1s) your animation will be prerendered before it fires, thus should be smoother:
message.style = "transition: all 10s linear .1s; transform: translateX(calc(-100vw - 100%))"
On first view, it could be the calc() section with vw and %. This mix caused sometimes trouble in my projects, for you get non-integers, which will be rounded automatically by the browser. So I changed the 100% to 100vw in your codepen. The result was a much smoother animation - at least in Chrome.
In addition to using translate3d instead of translateX as pointed out by #sol, I was able to improve the performance by using position: absolute and a fixed width for .Segment__message (plus a fixed height for the .Segment).
On my machine the performance degradation is very minor (even with 6x CPU slowdown) so it was difficult to test accurately, however my guess is that since an item is positioned using position: relative; (or position: static as per #sol's example) then it might cause some style recalculations as the item's (and the adjacent DOM element - in this cause a pseudo element) position shifts within it's parent container.
https://codepen.io/anon/pen/XoZRwr
I've been experimenting with a way to get a page element to overlap the elements on either side of it and stay perfectly centered between them. My solution was to declare position:relative and set negative margin values roughly equal to 50% of the element's width, but the closest I've been able to come is to half the element's percentage of its parent's width:
<!DOCTYPE html>
<html>
<head>
<style>
.clap {
position:relative;
margin:auto -16.66%; // This element's share of the entire parent's width = 33.33%
color:#f00
}
</style>
</head>
<body>
<center>
<span style="display:inline-block">1234567890<span class="clap">1234567890</span>1234567890</span>
</center>
</body>
</html>
I'm trying to find a CSS-only solution that will use the width of the element itself, not the width of the container. I can't use JavaScript to do this because I plan to use it as a MathJaX fix by embedding it in a \style command. (As far as I know, MathJaX does not provide for embedded HTML or JavaScript code within its formulas, so you see why this must be CSS-only. I know it's possible with scripting. Is it possible with CSS, or is my endeavor hopeless?
Update: Thanks to a suggestion from #Daiwei, I think I'm on the road to the right solution. Thanks for all your answers. Here is the revised code:
.clap {
position:absolute;
display:inline-block;
transform: translate(-50%,0);
color:#f00 // for contrast
}
I'd love to show you the results, but I can't upload a picture. Sorry.
Another update: The solution I presented above works best in an HTML/CSS context, but it breaks in a MathJaX array, matrix, or similar tabular environment. Specifically, if the element is too long, it clips on the left side. Relative positioning moves the element halfway to the left but leaves a gaping space where it used to be! Any ideas for patching it up?
One pure CSS solution is to use transform.
element
{
position: relative;
top: 50%;
transform: translateY(-50%);
}
Notes:
You can use top: 50%; for vertical and left: 50%; for horizontal.
You would then use translateY(-50%) for vertical and translateX(-50%) for horizontal centering.
You can also use this trick to align elements to the bottom or right of it's parent, like in a table-cell by using 100% instead of 50% in the css.
If you want to support older browsers, then you'll need to use prefixes for transform. I highly recommend autoprefixer in your workflow.
As the size of the element is only known after it has been styled, how should the style be able to use it? Imagine this: Some element has a width of 200% of it's own width (=double size than "normal") set in CSS. One of it's children has its width set to 100% of the parent (=our element). The default width of an element is determined by its content. Content's of our element are as width as the element itself. Our element has no width yet however, as we're waiting for it to get some default, so we can double that one. Result: Nothing will ever get any width.
Therefore: What you're trying to do is not possible. But CSS3 has its calc, maybe you can get closer to what you want to acheive using it?
I don't know if this is what you wanted to do, but here is a demo: http://cdpn.io/bgkDf
HTML
<div class="container">
<div id="box-left"></div>
<div id="box-overlap">
<div id="box-overlap-inner"></div>
</div>
<div id="box-right"></div>
</div>
CSS
.container > div {
height: 50px;
float: left;
}
#box-left {
width: 40%;
background-color: red;
}
#box-right {
width: 60%;
background-color: green;
}
#box-overlap {
width: 0;
}
#box-overlap-inner {
position: relative;
z-index: 10;
height: 50px;
width: 50px;
transform: translate(-50%,0);
background-color: rgba(0,0,255,.5);
}
"Using element's own width for calculation or percentage" In general:
(Maybe not the best solution for your issue, but an answer to your question)
At the moment,the attr function doesn't work in Chrome. That would have been nice.
But you can use variables, if you either set the parent attribute yourself, or are able to use a predefined one. That way you can use the calc() function to calculate your child attribute.
Here is an example, using the browser defined viewport size, to calculate the width of an element:
<!DOCTYPE html>
<html>
<head>
<style>
:root {
--module-size: 33vw;
}
.clap {
display:inline-block;
width: calc(var(--module-size) / 2);
color:#f00;
border: 1px solid;
}
</style>
</head>
<body>
<center>
<span style="display:inline-block">1234567890
<span class="clap">1234567890</span>
1234567890</span>
</center>
</body>
This can be used in many interesting ways, to streamline your CSS. For instance with the #media style...
And if someone (like me) was trying to center the element by its parent, use this simple style:
.clap {
position:absolute;
left: 50%;
transform: translate(-50%,0);
}
What about converting the content to divs and enclose each within another div to use
margin: auto
?
Example (each super div within its own colour and shifted a little in height for clarity):
<html>
<head>
<style>
.dl
{
position: absolute;
left: 0px;
top: 0px;
max-width: 50%;
width: 50%;
text-align: left;
background: red;
opacity: 0.5;
}
.dls
{
margin: auto;
}
.dc
{
position: absolute;
left: 25%;
top: 10px;
max-width: 50%;
width: 50%;
text-align: center;
background: green;
opacity: 0.5;
color: white;
}
.dcs
{
margin: auto;
}
.dr
{
position: absolute;
right: 0px;
top: 20px;
max-width: 50%;
width: 50%;
text-align: right;
background: blue;
opacity: 0.5;
color: white;
}
.drs
{
margin: auto;
}
.overall-width
{
position: absolute;
left: 0%;
width:100%;
height: 20px;
margin: auto;
}
</style>
</head>
<body>
<div class="overall-width">
<div class="dl">
<div class="dls">
1234567890
</div>
</div>
<div class="dc">
<div class="dcs">
1234567890
</div>
</div>
<div class="dr">
<div class="drs">
1234567890
</div>
</div>
</div>
</body>
</html>
let me preface this by saying I don't really know CSS at all. I'm trying to make a performance bar using CSS and Javascript and what I have so far creates a bar background and then a bar inside that one that fills it up to the specified percentage. My problem is that the "inner bar" comes down from the top instead of up from the bottom. I could just subtract the percentage from 100 and take the absolute value, but that seems like kind of a dirty hack. I would like to just see how I could make this be aligned at the bottom and "grow" up as the height grows rather than starting at the top and growing down.
CSS Code
.cssSmall .performanceBack
{
position: absolute;
z-index: 1;
height: 20px;
width: 18px;
top: 4px;
left: 81%;
background-color: Brown;
}
.cssSmall .performanceBar
{
font-size: 6px;
vertical-align: top;
background-color: Orange;
}
Javascript code
this.performanceBack = gDocument.createElement("performanceBack");
this.performanceBack.className = "performanceBack";
div.appendChild(this.performanceBack);
this.performanceBar = document.createElement('div');
this.performanceBar.className = 'performanceBar';
//Hard coded value for testing
this.performanceBar.style.height = '30%';
this.performanceBack.appendChild(this.performanceBar);
Thanks.
Since you've already set .performanceBack to position: absolute I would do the same for .performanceBar but set the bottom property to 0 which will make it anchored to the bottom-left corner of .performanceBack.
.cssSmall .performanceBar
{
font-size: 6px;
background-color: Orange;
position: absolute;
left: 0;
bottom: 0;
width: 100%;
}
You can see it in action at http://jsfiddle.net/U5V2b