CSS perspective on a long, scrollable div - css

I've got a click style that involves tilting the element via a 3D rotate when clicked on. Here's what it looks like:
And here is a GIF of the effect working properly with a short list!
I have perspective on the parent div set at about 1500px, and the list div is set to inherit perspective. When this scrollable div gets really long, though, you start to see effects like this when clicking elements toward the bottom of the list:
I'm assuming this is because the perspective is applied to the entire height of the div, rather than just the visible height. I tried to resolve this by having the perspective of the list div inherit from the parent div (who's height is only the visible area), but this had no effect.
Any ideas on how to solve this?
Thank you!
EDIT: Relevant HTML:
<div class="container">
<ul class="artists">
<li>38 Special</li>
<li>A Flock Of Seagulls</li>
<!-- etc. -->
</ul>
</div>
Relevant CSS:
div.container {
position: relative;
height: calc(100% - 120px);
overflow: hidden;
perspective: 1500px;
}
ul.artists {
position: absolute;
top:0;
bottom:0;
left:0;
right:0;
/* Animation stuff, list styles, etc */
perspective: inherit;
overflow-y: auto;
overflow-x: hidden;
}
When pressed, a style like this is applied to the list item:
{
transform: rotate3d(4.05, 6.1635, 0, 15deg);
}
EDIT: Repro here:
http://codepen.io/anon/pen/LqAhK
Notice how as you scroll down the list, the perspective is applied as though the viewport is as high as the list itself, rather than the container - resulting in a different effect depending on your position in the list! How can I get perspective to be applied on the list items using the dimensions of the container only?
My best workaround would be to freeze the list and set a static height on the click event, but that has some side effects and is a somewhat hacky solution!

I'm not sure if this is what you're looking for, but...
ul.list li {
perspective: inherit;
}
...changing it so that the <li> elements themselves are what reset the perspective, rather than the container <ul>, seems to make all the elements appear the same.
http://codepen.io/anon/pen/zGpKk

Related

How to use transform: translateY on a child while automatically resizing the parent?

Let be a division containing a second division. The first one does not have a remarkable CSS rule; the second one is defined by its width and height. Both are coloured.
A Y-translation of several pixels is applied to the child division as follows:
https://codepen.io/anon/pen/KbjLMw
Sources
HTML
<div id="parent">
<div id="child"></div>
</div>
CSS
#parent {
background: red;
}
#child {
background: yellow;
width: 100px;
height: 100px;
transform: translateY(253px);
}
Question
We would like the parent division to see its height increased according to the movement of its child division. How could such a result be achieved? The use of transform: translateY(xyz) is desirable but not necessary.
We would like the parent division to see its height increased according to the movement of its child division. How could such a result be achieved?
That is not possible using transform, because that keeps the space the element would have taken originally reserved, but it does’t make it take space at the new position.
You can get the parent to grow, if you move the child via margin-top: 253px; instead. (Of course that leads to a collapsing margins situation here, but that can be fought f.e. by making the parent inline-block or setting overflow:hidden.)
add margin-top: 90px; to child and add padding-top: 1px. hope this is what you are looking for. thanks
link for your ref.
https://codepen.io/Xenio/pen/XOXJGz

3D transforms take up space even if taken out of flow?

I'm rotating a div in 3D space. It's pretty simple:
<div class="holder">
<div class="box">
<p>This is some text.</p>
</div>
</div>
.box {
background: orange;
color: #fff;
font-size: 6em;
transform: rotateY(60deg);
padding: 20px;
position: absolute;
}
.holder {
perspective: 300px;
max-width: 600px;
margin: 0 auto;
}
I notice that in IE11 and Firefox, if the transform makes the shape run out of the viewport, it will display scrollbars. This happens even if the item is out of the flow, by setting position: absolute. In Chrome, no scrollbars are displayed.
My understanding was that 3D transforms don't take up any additional space than the non-3D version of the item, so I'm not sure whey scrollbars are appearing in some browsers. Is this the correct behavior?
Yes, this is correct behavior as per spec: http://dev.w3.org/csswg/css-transforms-1/#transform-rendering
For elements whose layout is governed by the CSS box model, the transform property does not affect the flow of the content surrounding the transformed element. However, the extent of the overflow area takes into account transformed elements. This behavior is similar to what happens when elements are offset via relative positioning. Therefore, if the value of the overflow property is scroll or auto, scrollbars will appear as needed to see content that is transformed outside the visible area.
Common workaround for this kind of behavior would be setting overflow: hidden on html element and then reseting it to auto or scroll lower in the DOM, based on your needs.

Width transitioning from fixed size to "auto" using CSS without Javascript

I'm having a bit of a problem making script-less CSS-only animated transition of an element that's initially set to a fixed width and should expand on mouse over to auto width according to content in it. When mouse goes out it should collapse back to fixed width.
Let's say I have a menu:
<menu>
<li>Item</li>
<li>Item with long text</li>
</menu>
Initially it would display as a collapsed 50px wide vertical bar with icons only. When one mouses over it reveals icon labels.
This is a simplified example of what I'm trying to achieve. First menu is the one that needs to transition and second one is there just to show what auto width should be for this amount of content.
Problem
This is just part of the whole CSS that plays an important role here:
menu {
width: 50px;
}
menu:hover {
width: auto; /* setting to other fixed width works as expected */
}
The problem is that when you set width to auto one of the two will happen:
Browser animates from fixed width 0 (Chrome) - if we then add min-width it does next one
Browser doesn't animate anything just applies new style
You can make use of the max-width trick, it's not perfect, but it gets around the problems with transitioning a numeric value to a string state:
http://jsfiddle.net/Cqmuf/1/
(the above has been updated with float:left)
The downside to this method is that you have to set a max width for your menu, but then I usually find that this is a good thing to do anyway.
markup:
<div class="menu">
[i] Hello
[i] There
</div>
css:
div a {
display: block;
overflow: hidden;
white-space: nowrap;
}
.menu {
transition: all 2s;
max-width: 17px;
/*
here you can set float:left or position:absolute
which will force the menu to collapse to it's minimum
width which, when expanded, will be the actual menu
item widths and not max-width.
*/
float: left;
}
.menu:hover {
/*
If you have the possibility of varied widths, i.e. multilingual
then make sure you use a max-width that works for them all. Either
that or do what a number of multilingual sites do and set a body
class that states the current language, from there you can then
tailor your max-width differently e.g. wider for German.
*/
max-width: 300px;
}
Example of seperate dimensions for multilingual:
.lang-de .menu:hover { max-width: 400px; }
.lang-gb .menu:hover { max-width: 300px; }
So instead of transitioning the width, you are actually modifying the max-width property, which you can set a fixed value to more easily, all because it will only come into use when this limit has been reached, and remains invisible until then.

CSS - position: absolute; - auto height

I am having a problem with some div's
The outer div has a min-height, but the inner divs are all varying heights. Because the inner divs are absolute positioned, they do not affect the outer divs height. Is there a way to make these inner divs affect the height of the outer div?
The reason I am styling these divs with position:absolute is so that they all start at the top of the container div.
As far as I know, there's no way for absolutely positioned child elements to affect the height of their statically, or relatively positioned parent elements using only CSS. Either:
Reorganize so that the child elements remain in the document flow
Use JavaScript on load of the page to set the height of the parent to the height of the largest child
This issue is common in fade-in/fade-out JavaScript slideshows, and from what I've seen either 1) the height of the parent container needs to be defined or 2) the parent container's height is set dynamically for each slide.
I recently had this problem with a fade in/out CSS transition slideshow, and ended up solving it by giving the first child element position: relative; and the others position: absolute; top:0; left: 0; which ensures that the containers height is the same as the height of first element. Since my CSS transition slideshow uses the opacity property the container dimensions never changes during the course of the slideshow.
Alas, since I also needed to supply a javascript fallback for older browsers I had to set the container height for these browsers anyway (because of jQuerys fadeIn/fadeOut actually setting display: none; I would guess).
Here is a long overdue cross-browser solution to your problem. No more static width, no more em hack.
<style>
/* clearfix */
.container:after {
content: '';
display: table;
clear: left;
}
.page {
float: left; /* display side-by-side */
width: 100%; /* be as wide as parent */
margin-right: -100%; /* take up no width */
}
</style>
<div class="container">
<div class="page"></div>
<div class="page"></div>
</div>
After searching for a solution to this problem for so long, I am baffled to see how simple it is. Granted, the .page elements are not absolutely positioned. However, all the same goals can be achieved through this method, with almost no pain or sacrifice.
Here's a demo: https://jsfiddle.net/eqe2muhv/
This also works for inline-blocks, of course. Though you might need to set the font-size or letter-spacing of the container to 0. I would also recommend using vertical-align: top on the .page, to simulate a regular block element.
Here's a demo: https://jsfiddle.net/dzouxurs/8/
Try to use display: inline-table, height: auto; .. it works for me
I think you should position them relatively and just change "vertical-align" to "top" in the interior divs. Then you won't have the issue of messing with abs divs.
You can simply float the divs if you want them to be on the same horizontal plane.
i've done this task without any JS. Only, by CSS:
.frame {
max-height: calc(100vh - 283px); // 283px gives me some space at the botoom of the frame
}
Maybe u can try max-height: calc(100% - 50%); it will work if the content that should be in the middle of the screen/div is super short/small.
position:absolute;
top:0;
bottom:0;
margin:auto;
width:auto;
height:auto
max-height: calc(100% - 50%);
...etc...
Test display: inline-block on the element that need auto height.

Seeking CSS Browser compatibility information for setting width using left and right

Here's a question that's been haunting me for a year now. The root question is how do I set the size of an element relative to its parent so that it is inset by N pixels from every edge? Setting the width would be nice, but you don't know the width of the parent, and you want the elements to resize with the window. (You don't want to use percents because you need a specific number of pixels.)
Edit
I also need to prevent the content (or lack of content) from stretching or shrinking both elements. First answer I got was to use padding on the parent, which would work great. I want the parent to be exactly 25% wide, and exactly the same height as the browser client area, without the child being able to push it and get a scroll bar.
/Edit
I tried solving this problem using {top:Npx;left:Npx;bottom:Npx;right:Npx;} but it only works in certain browsers.
I could potentially write some javascript with jquery to fix all elements with every page resize, but I'm not real happy with that solution. (What if I want the top offset by 10px but the bottom only 5px? It gets complicated.)
What I'd like to know is either how to solve this in a cross-browser way, or some list of browsers which allow the easy CSS solution. Maybe someone out there has a trick that makes this easy.
The The CSS Box model might provide insight for you, but my guess is that you're not going to achieve pixel-perfect layout with CSS alone.
If I understand correctly, you want the parent to be 25% wide and exactly the height of the browser display area. Then you want the child to be 25% - 2n pixels wide and 100%-2n pixels in height with n pixels surrounding the child. No current CSS specification includes support these types of calculations (although IE5, IE6, and IE7 have non-standard support for CSS expressions and IE8 is dropping support for CSS expressions in IE8-standards mode).
You can force the parent to 100% of the browser area and 25% wide, but you cannot stretch the child's height to pixel perfection with this...
<style type="text/css">
html { height: 100%; }
body { font: normal 11px verdana; height: 100%; }
#one { background-color:gray; float:left; height:100%; padding:5px; width:25%; }
#two { height: 100%; background-color:pink;}
</style>
</head>
<body>
<div id="one">
<div id="two">
<p>content ... content ... content</p>
</div>
</div>
...but a horizontal scrollbar will appear. Also, if the content is squeezed, the parent background will not extend past 100%. This is perhaps the padding example you presented in the question itself.
You can achieve the illusion that you're seeking through images and additional divs, but CSS alone, I don't believe, can achieve pixel perfection with that height requirement in place.
If you are only concerned with horizontal spacing, then you can make all child block elements within a parent block element "inset" by a certain amount by giving the parent element padding. You can make a single child block element within a parent block element "inset" by giving the element margins. If you use the latter approach, you may need to set a border or slight padding on the parent element to prevent margin collapsing.
If you are concerned with vertical spacing as well, then you need to use positioning. The parent element needs to be positioned; if you don't want to move it anywhere, then use position: relative and don't bother setting top or left; it will remain where it is. Then you use absolute positioning on the child element, and set top, right, bottom and left relative to the edges of the parent element.
For example:
#outer {
width: 10em;
height: 10em;
background: red;
position: relative;
}
#inner {
background: white;
position: absolute;
top: 1em;
left: 1em;
right: 1em;
bottom: 1em;
}
If you want to avoid content from expanding the width of an element, then you should use the overflow property, for example, overflow: auto.
Simply apply some padding to the parent element, and no width on the child element. Assuming they're both display:block, that should work fine.
Or go the other way around: set the margin of the child-element.
Floatutorial is a great resource for stuff like this.
Try this:
.parent {padding:Npx; display:block;}
.child {width:100%; display:block;}
It should have an Npx space on all sides, stretching to fill the parent element.
EDIT:
Of course, on the parent, you could also use
{padding-top:Mpx; padding-bottom:Npx; padding-right:Xpx; padding-left:Ypx;}

Resources