How to make this list item "zoom" - javascript

I am trying to make list items "zoom" when selected. I'm having trouble finding the best way to make this happen. I'm using GSAP and the javascript is working just fine, but I'm having a hard time finding which property would best achieve the desired "zoom" effect.
https://jsfiddle.net/Leahp374/1/
At the moment, I am attempting to use CSS perspective and translate3d to move the item closer in the Z direction. However, since the perspective-origin is at 50% 50%, and since the list item is centered in its parent container, the first and last list items move towards the top and bottom, respectively. Instead, I'd like them to all behave as the middle list item.
Using something like font-size will cause the element to 're-center' based on it's new width, which is not desirable.
What is the best way to achieve the "zoom" effect?

Is this the desired 'zoom' effect that you are looking for?
You can use scale transform along with transform origin to get the desired zoom effect.
html, body {
height: 100%;
}
div {
perspective: 600px;
width: 100%;
height: 100%;
background: red;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
}
li:nth-child(1) {
transform: scale(1.5);
transform-origin:-40%;
}
<div>
<ul>
<li>One</li>
<li>Two</li>
<li>Three</li>
</ul>
</div>

Related

Why the sizes of those images are causing the layout shift? CSS? JavaScript?

https://codesandbox.io/s/stackoverflow2-bdiq2r
I really don't get it why the different sizes of the images are causing the layout shift. I wrote the code considering the difference in size of image for the responsive layout.
The problem is really strange that when you slide the carousel using the button on there, and the whole carousel is inside the viewport, there's no problem. But when you do slide it when part of the carousel is outside the viewport, that layout shift problem occurs.
I've been holding this bug for the whole day already, but really don't know why that size difference is causing the problem in this code, and how to make this work exactly as it is working when the whole carousel is inside the viewport. Is this my React code problem? or my CSS? There's no problem if I set height: 100% for .img but the way of this carousel working gets different.
I attach 2 images to describe the problem more intuitively.
As you can see the carousel gets moved down as soon as you slide to the image of different size (The only purple image has a different size).
It looks like this might be caused by align-items behavior when the images have different natural height.
In styles.module.css, try set align-items: stretch on .img-container and set object-fit: scale-down on .img to fix this.
Example: (with live demo on: codesandbox)
.img-container {
width: 100%;
display: flex;
justify-content: center;
/* 👇 Changed from 'center' to 'stretch' */
align-items: stretch;
text-align: center;
position: relative;
transform: skewY(0.001deg);
color: white;
font-weight: bold;
font-size: 2rem;
}
.img {
max-width: 100%;
max-height: 100%;
/* 👇 Changed from 'contain' to 'scale-down' */
object-fit: scale-down;
}

Container size doesn't shrink with child scale

I'm trying to create a custom drop down menu in ReactJs. When a user clicks the heading, a list of items appears below it. This works but I want the div that contains both the heading and the list (.db-container) to in increase its height depending on if the list (.db-list) is visible or not. I can use display:none/block or position:absolute/relative with transform:scaleY(0)/scaleY(1) on .db-list but then I cannot animate it or use transitions. I've tried using visibility:hidden/visible which does hide the list but the container remains its full size.
I am using ReactJs and in the code snippet below, the handleClick() function just changes isVisible from true to false and vice versa.
.db-container {
display: flex;
flex-direction: column;
justify-content: flex-start;
}
.db-list {
transform: scaleY(0);
transform-origin: top center;
position: absolute;
}
.visible-true {
transform: scaleY(1) !important;
position: relative !important;
}
<div className='db-container'>
<h3 className='db-name' onClick={handleClick}>Headinf</h3>
<ul className={`db-list visible-${isVisible}`}>
<li>One</li>
<li>Two</li>
<li>Three</li>
<li>Four</li>
</ul>
</div>
Is there a way to get .db-container to change its height depending on the visibility of .db-list and use animations or transitions?
Use max-height and overflow:hidden. These are animatable. Needs a bit of tidying up but you'll get the general idea. Setting max-height means the element will just size itself to the content as long as you set it to a high enough value. (I've made it transform on :hover but you can change it to a click in react)
.db-container {
display: flex;
flex-direction: column;
justify-content: flex-start;
}
.db-list {
max-height:0px;
overflow: hidden;
transition: max-height 1s;
}
.db-name:hover + .db-list {
max-height:1000px;
}
Instead of shrinking, you can use position:absolute then delay your component from re-rendering when hiding for a few millisecond then animate.
I got this problem when I built a custom drawer menu. However, when I hide the component it doesn't animate because you can't animate what you can't see. So I had to delay the component re-render then set right to a negative number to move it out of the view port visible part with animation. After that hide the component.
If you use height(to hide by shrinking); it works, but for a second you will see the component children get misplace and it doesn't look great.

css flex column auto height

I am creating a mega menu trying to keep to current standards; CSS, jquery, bootstrap.
Google Images - Mega Menu
My menu is for product categories, which I want dynamically created in columns newspaper style. Easy enough, I have that working nicely. It requires a fixed height, which makes it overflow horizontally.
My current thinking is to, onload, increase the heights of each sub menu until there is no horizontal overflow. I can get it working with some manual intervention, which defeats to purpose of a dynamic layout.
.container {
width: 800px;
height: 100px;
display: flex;
flex: 1 1 auto;
}
.container .wrap {
display: flex;
flex: 1 1 auto;
flex-flow: column wrap;
align-content: flex-start;
}
.container .wrap .item {
width: 150px;
}
<div class="container">
<div class="wrap">
<div class="item">Item 1<br>a<br>b</div>
<div class="item">Item 2<br>a</div>
<div class="item">Item 3<br>a<br>b<br>c<br>d</div>
<div class="item">Item 4<br>a</div>
<div class="item">Item 5<br>a</div>
</div>
</div>
This style works perfectly aligning items top to bottom, left to right, as required.
Now I am trying to increase the height of each sub menu as required. Best solution is to detect width overflow and increase height to compensate.
I've tried native JS and jQuery, I seem to be getting stuck running it in a function. I can detect overflow and increase height, as my code below. What I want is to have the if statements in a loop and exit when no more overflow, and end up with a perfect fit.
EDIT
Current working solution
$(function () {
$(".container").each( function( index, element ){
var my_height = $(element).outerHeight();
if( $(element).prop('scrollWidth') > $(element).outerWidth() ) {
while( $(element).prop('scrollWidth') > $(element).outerWidth() )
{
my_height += 100;
$(element).css('height', my_height + "px");
}
}
});
});
Works exactly as intended.
EDIT
Updated question. Is there a better solution? Something that doesn't involve looping over every item every page. Pure CSS would be nice, but don't think it's possible just yet.
Solved my transition issue. When trying to update the height in a loop as above, transition CSS interferes and creates an infinite loop. Was an easy fix, I added a new class to .container .transition and added $(element).removeClass("transition"); to the start or the loop and $(element).addClass("transition"); to the end. This removes the transition CSS from the inner loop and adds it back at the end.
FINAL EDIT
My first attempt was using css columns, but I couldn't get it working to my spec. It wasn't until reading the accepted answer below I revisited columns and after some testing got it working.
Ref https://developer.mozilla.org/en-US/docs/Web/CSS/columns
There is a way of doing this using pure CSS using the column CSS properties:
Base CSS:
.container {
width: 800px;
}
.container .wrap {}
.container .wrap .item {
width: 150px;
}
To have columns of a fixed width:
.container .wrap {
column-width: 125px;
}
To have a set number of columns:
.container .wrap {
column-count: 5;
}
JSFiddle
Another answer giving details about browser support

Setting a max-height of page-height for a dropdown

Say you have a dropdown with a lot of options that overflow the page height. I know I can use overflow: auto to make it scroll, but only if I set it a max-height. How do I set a max-height that ensures the element won't overflow the browser window?
Like in this image
The left is what it's like now. Dropdown overflows page. The right is what it should be like -- the dropdown is resized to be height of just under the page height.
I've tried setting max-height to different values like 45vh since the dropdown is about halfway down the page, but this needs to fit all types of screen sizes so isn't flexible enough.
CSS solutions preferred in this case.
You can calculate the current distance between the dropdown and the bottom of the page (https://stackoverflow.com/a/7656176/5370933) and append styles with this value.
.myDropdown {
max-height: myDistance;
overflow: scroll
}
I think something like that could works. But you will have to use some JS to get the distance dynamically (depend on the user screen and/or user scroll before the dropdown opening...)
If I understood correctly the layout of your web page, the dropdown is the last element (well maybe) in the page.
What you could do is, first, add this lines to your main page container:
#page {
min-height: 100vh; /* Or the value you like most */
}
Now we have access to the full height of the document.
Next, you can simply use flexbox's space-between or space-around value to keep the dropdown on the bottom of the page (like footers).
But now, you want a little space between the end of the page and the dropdown. Simply add a margin-bottom and its done.
Now be aware that, I understand that there may be a footer or something below the dropdown. You can implement this solution in any container.
This isn't a bug-free solution, but it doesn't require javascript.
Here is a working example.
function _test_add(){
document.getElementById("dropdown").innerHTML += "<li>Item</li>";
}
#page {
min-height:100vh;
display:flex;
flex-direction: column;
justify-content: space-between;
}
#addbtn {
margin:0 auto;
}
/*
* Fictif Content
*/
#main-content {
height: 50vh;
display:flex;
justify-content:center;
align-items:center;
background-color:gray;
}
#dropdown {
min-height: 8em;
max-height: 18em;
background-color:#f1f1f1;
padding: 0;
list-style-type: none;
overflow: auto;
margin-bottom:4em;
border: solid black 2px;
}
#dropdown li {
padding:1em;
}
#dropdown li:nth-child(odd) {
background-color: #fafafa;
}
<div id="page">
<div id="main-content">
Main Content
</div>
<button id="addbtn" onclick="_test_add()">[TEST] Add items in dropdown</button>
<ul id="dropdown">
<li>Item</li>
<li>Item</li>
<li>Item</li>
</ul>
</div>

How do I expand selector width from center (or other efficient alternatives)?

I've got a navigational bar (#nav_bar), which has the following CSS properties:
#nav_bar {
background: url(../images/navbar.png) repeat-x;
width: 100%; height: 50px;
margin-bottom: 20px;
}
It takes the width of #wrap which is 1024px wide and has margin: auto;, however I would like to expand it so that it will fit all screen sizes 100%. I attempted to set width: 500%; just to see what it would do, then I realized that it expands from the left -> right, rather than both ways from the center.
So, what I'm asking is;
Is it possible to have an element expand from the center, then
perhaps I could set the max-width property or use javascript to
find out the visitors screen resolution then assign the width from
there; without major inefficiencies, i.e. extended load times/cross-browser compatibility issues?
Just for reference, a link to the particular page I'm talking about
Any answers will be greatly appreciated ;)!
Simply move your #nav_bar out of the #wrap.
Alternatively you can make your #nav_bar have position: absolute; left: 0px; width: 100%; in CSS, that will work too.
Why don't you use CSS3 Media Queries, to find out about screen size of your clients.
If your #nav-bar is a block-level element, like a div, a ul or a p element, then it by default would take the whole width of its container. Thus you don't need to set width: 100%; there. Also, you can use text-align: center; to center align the content.
In your case, you can use absolute positioning with overflow: visible attribute, and set the width of the menu. Also, you may simply extract your #nav-bar out of the wrap, to let it take the whole space.
use margin: auto
you can see an example here: http://jsfiddle.net/s995c/4/

Categories