CSS Scroll Perspective on Nested Elements - html

The following code produces a perspective effect that changes the angle you are looking at the element, as you scroll:
<div class="parent">
<div class="box"/> </div>
<div class="box"/> </div>
<div class="box"/> </div
</div>
* {
height: 100%;
overflow: hidden;
}
.nesting {
height: 3000px;
}
.parent {
overflow: scroll;
perspective: 200px;
height: 100vh;
}
.box {
width: 100px; height: 100px;
margin: 100px auto;
border: 5px solid black;
transform: rotateX(50deg);
}
Codepen: https://codepen.io/Davste93/pen/ZEydJeK
However this is not very practical for real-world situations, because the moment you add an element in between the parent and transformed element (see: nesting), it breaks:
<div class="parent">
<div class="nesting">
<div class="box"/> </div>
<div class="box"/> </div>
<div class="box"/> </div>
</div>
</div>
Isn't this what preserve-3d, is meant to do? Nothing seems to work.
Is there a way to get CSS perspective animations to work on scroll with elements in between?
I know I can achieve the same effect with perspective-origin and javascript, but I would like to keep this in pure CSS if possible.

I found out a few things on this journey:
overflow: hidden breaks perspective, even when there's preserve-3d
preserve-3d is needed on any nested elements
Angular components (unless they have display: block) do not pass down perspective.
Working example:
<div class="parent">
<div class="nesting">
<div class="box"/> </div>
<div class="box"/> </div>
<div class="box"/> </div>
<div class="box"/> </div>
<div class="box"/> </div>
<div class="box"/> </div>
</div>
</div>
* {
height: 100%;
}
html {
overflow: hidden;
}
.nesting {
transform-style: preserve-3d;
}
.parent {
overflow: scroll;
perspective: 200px;
height: 100vh;
}
.box {
width: 100px; height: 100px;
margin: 100px auto;
border: 5px solid black;
transform: rotateX(50deg);
}
https://codepen.io/Davste93/pen/jOwjxOP

Related

CSS parallel columns

I am trying to create three parallel columns of the same width (33.3%) and height (100%). In each column, I want to split it vertically into 80% - 20% ratios. The code below seems straight forward, but I couldn't achieve that. If someone could advise?
Note that I keep the flex and wrap stuff in the inner parts because I will be adding elements into them later. Thanks.
#outer-container {
height: 500px;
width: 100%;
}
#left-container, #mid-container, #right-container {
background-color: #495052;
width: 33.3%;
height: 100%;
border: 1px solid;
border-color: #cae329; /*Bright citrus*/
overflow: auto;
}
#left-top-container, #mid-top-container, #right-top-container {
display: flex;
flex-wrap: wrap;
background-color: #495052;
width: 100%;
height: 80%;
overflow: auto;
}
#left-bottom-container, #mid-bottom-container, #mid-bottom-container {
display: flex;
flex-wrap: wrap;
background-color: yellow;
width: 100%;
height: 20%;
border: 1px solid;
border-color: #cae329;
overflow: auto;
}
<div id="outer-container">
<div id="left-container">
<div id="left-top-container">
</div>
<div id="left-bottom-container">
</div>
</div>
<div id="mid-container">
<div id=mid-top-container">
</div>
<div id="mid-bottom-container">
</div>
</div>
<div id="right-container">
<div id="right-top-container">
</div>
<div id="right-bottom-container">
</div>
</div>
</div>
You've got a few typos in your code. Notably a missing quotation mark on one of your ids in your HTML (mid-top-container), and a duplicate rule for #mid-bottom-container instead of #right-bottom-container.
Also, your columns are still display:block, so they will not stay on the same line. I changed them to display: inline-block; to fix that. Their widths should be calc(100% / 3) to make them exactly one third of the width. They need box-sizing: border-box to make the padding/border part of the width figure, and finally, the parent #outer-container needs font-size:0 to remove any white space between the columns.
#outer-container {
height: 500px;
width: 100%;
font-size: 0;
}
#left-container, #mid-container, #right-container {
display: inline-block;
background-color: #495052;
width: calc(100% / 3);
height: 100%;
border: 1px solid;
border-color: #cae329; /*Bright citrus*/
overflow: auto;
box-sizing: border-box;
}
#left-top-container, #mid-top-container, #right-top-container {
display: flex;
flex-wrap: wrap;
background-color: #495052;
width: 100%;
height: 80%;
overflow: auto;
}
#left-bottom-container, #mid-bottom-container, #right-bottom-container {
display: flex;
flex-wrap: wrap;
background-color: yellow;
width: 100%;
height: 20%;
border: 1px solid;
border-color: #cae329;
overflow: auto;
}
<div id="outer-container">
<div id="left-container">
<div id="left-top-container">
</div>
<div id="left-bottom-container">
</div>
</div>
<div id="mid-container">
<div id="mid-top-container">
</div>
<div id="mid-bottom-container">
</div>
</div>
<div id="right-container">
<div id="right-top-container">
</div>
<div id="right-bottom-container">
</div>
</div>
</div>
Though there are some Typos. But some un-necessary ids and CSS is also present in the Code.
You may try CSS-GRIDS and Flexbox (in a better way) to achieve the same with much lesser code so that the performance of the app increases.
Have removed all extra selectors.
CODEPEN: https://codepen.io/emmeiWhite/pen/RwGyBLO
*{
margin:0;
padding:0;
box-sizing:border-box;
}
#outer-container {
height: 500px;
display:grid;
grid-template-columns:repeat(3,1fr);
width: 100%;
}
.column-wrapper{
display:flex;
flex-direction:column;
background-color: #495052;
border: 1px solid;
border-color: #cae329; /*Bright citrus*/
}
.top-section{
height:80%;
}
<div id="outer-container">
<div class="column-wrapper">
<div class="top-section">
left top
</div>
<div>
bottom
</div>
</div>
<div class="column-wrapper">
<div class="top-section">
mid-top
</div>
<div>
mid-bottom
</div>
</div>
<div class="column-wrapper">
<div class="top-section">
right-top
</div>
<div>
right-bottom
</div>
</div>
</div>

Make only part of child elements overflow:visible

I need to have overflow-x: scroll like on first part of my image, and overflow visible to div bigger than its parent like on part 2 of my image.
So my problem is when I add overflow:visible to parent div, all overflows inside it are visible. I want to make overflow:visible, but keep overflow-x:scroll on parent div. Is it even possible?
HTML:
<div id="wrapper">
<div class="content">
<div class="child">
<button onclick="action(this)" class="triggerBtn">Click</button>
</div>
</div>
<div class="content">
<div class="child">
<button onclick="action(this)" class="triggerBtn">Click</button>
</div>
</div>
<div class="content">
<div class="child">
<button onclick="action(this)" class="triggerBtn">Click</button>
</div>
</div>
<div class="content">
<div class="child">
<button onclick="action(this)" class="triggerBtn">Click</button>
</div>
</div>
<div class="content">
<div class="child">
<button onclick="action(this)" class="triggerBtn">Click</button>
</div>
</div>
</div>
CSS:
#wrapper {
height: 200px;
width: 400px;
white-space:nowrap;
overflow-x: auto;
overflow-y: hidden;
margin:auto;
background-color: rgb(240,240,240);
position: relative;
z-index: 1;
}
.content {
width: 200px;
height: 100%;
overflow-x: hidden;
display: inline-block;
position: relative;
z-index: 100;
background-color: rgb(200,200,200);
}
.child {
width: 200px;
height: 50%;
position: absolute;
left: 0;
top: 0;
/* transform: translateX(50%); */
background-color: #bada55;
border-radius: 5px;
z-index: 200;
transition: all .15s ease-in-out;
text-align: center;
}
div.child.active {
width: 400px;
left: -50%;
background-color: #111
}
Bunch of JS:
window.action = function(el) {
var parent = el.parentNode;
if(parent.classList.contains('active')) {
parent.classList.remove("active");
} else {
parent.className += " active";
}
};
a quick fix is to use !important on your child selectors, like so:
.parent {
overflow: visible;
}
.child {
overflow: hidden !important;
}
!important simply tells the system to use the style instead of inheriting the parent's styling. You can also use the immediate child selector >.

CSS for Individual Columns Scroll with Horizontal Scrolling

I am building a UI component that has columns of information. Each column needs to be individually scrollable. I have found that on SO.com before, but I am having trouble reconciling that with the other requirement - that the page scrolls horizontally to show columns that do not fit on screen.
I have the horizontal scrolling working but cannot get it to work in conjunction with individual column scrolling. The code:
#board {
float: left;
height: 98%;
max-height: 98%;
width: 4300px; /*smaller than columns to force horizontal scroll */
margin: auto;
border: none;
overflow-x: scroll;
}
#columns {
height: 98%;
float: left;
width: 4800px; /* need this much width */
margin: auto;
border: none;
overflow-x:auto;
}
.column {
float: left;
padding-bottom: 50px;
width: 240px;
height: 100%;
max-height: 100%;
padding: 5px;
padding-bottom: 100px;
margin-left: 5px;
overflow-y: auto;
overflow-x: hidden;
}
<div id="board">
<div id="columns">
<div id="col1" class="column">
<div class="card"> ...content... </div>
<div class="card"> ...content... </div>
<div class="card"> ...content... </div>
<div class="card"> ...content... </div>
</div>
<div id="col2" class="column">
<div class="card"> ...content... </div>
<div class="card"> ...content... </div>
<div class="card"> ...content... </div>
<div class="card"> ...content... </div>
</div>
<!-- 12-16 more columns -->
</div>
</div>
Edited to fix id vs class issue in html.
I tried to simplify your code to only include what's necessary to solve your problem, but it should work. There are a couple errors in your CSS too: you have a style for #boards but the outer container has a class boards not an id, and you have a style for #columns but the middle inner container has an id of positions.
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
.board {
height: 100%;
width: 200px;
overflow-x: scroll;
}
#columns {
height: 100%;
width: 500px;
white-space: nowrap;
}
.column {
vertical-align: top;
height: 100%;
display: inline-block;
width: 150px;
overflow-y: auto;
overflow-x: hidden;
}
.card {
height: 200px;
background: #F00;
margin-bottom: 5px;
}
<div class="board">
<div id="columns">
<div class="column">
<div class="card">...content...</div>
<div class="card">...content...</div>
<div class="card">...content...</div>
<div class="card">...content...</div>
</div>
<div class="column">
<div class="card">...content...</div>
<div class="card">...content...</div>
<div class="card">...content...</div>
</div>
<div class="column">
<div class="card">...content...</div>
</div>

Extend one div (among others) beyond parent container

I have a certaing layout of nested divs. One of them I would like to expand beyond its parent. However, with this nesting it's not that simple - I think.
Html:
<div class="wrapper">
<div class="gridcontent">
<div class="gcrow single-column">
<div class="gccolumn">
<div class="gccolumn-inner">
<div class="gcitem">
<p>Extend to .wrapper width</p>
</div>
</div>
</div>
</div>
</div>
</div>
I can't change the html, and there may be other .gcrows that need to stay inside the container. Is this possible to to at all?
Fiddle here.
I hope my question makes sense.
For your current HTML structure you can use .gcrow:first-child and set min-width: 100vw which is same as wrapper width if you remove default margin and padding from html, body.
You can use position: relative, left: 50% and to make it center just add transform: translateX(-50%), here is Fiddle
body,
html {
margin: 0;
padding: 0;
}
* {
box-sizing: border-box;
}
.wrapper {
width: 100%;
padding-left: 20px!important;
padding-right: 20px!important;
border: 1px solid pink;
}
.gridcontent {
width: 100%;
max-width: 1018px;
border: 1px solid #333;
margin: 0 auto;
}
.gcrow {
max-width: 100%;
width: 100%;
border: 1px solid #f00;
}
.gcrow:first-child {
min-width: 100vw;
position: relative;
left: 50%;
transform: translateX(-50%);
}
<div class="wrapper">
<div class="gridcontent">
<div class="gcrow single-column">
<div class="gccolumn">
<div class="gccolumn-inner">
<div class="gcitem">
<p>Extend to .wrapper width</p>
</div>
</div>
</div>
</div>
<div class="gcrow single-column">
<div class="gccolumn">
<div class="gccolumn-inner">
<div class="gcitem">
<p>Leave me alone</p>
</div>
</div>
</div>
</div>
</div>
</div>
Also its box-sizing: border-box not box-border
try something like this
.gcrow {
position: relative;
overflow: visible;
}
.gcitem {
position: absolute;
right: 0;
top: 0;
}

CSS overflow: auto in some elements don't work

I have Ios mobile app and using WebKit Safari. I have an container with items. Container must swipe up/down. Elements inside container - left/right. The problem is, when i set overflow: auto; to both - and container and elements, when i swipe elements - they works. But if i want swipe the hole container (up/down), it don't. I need to swap elements and container too Please help!
<div id="container">
<div id="data-container">
<div class="left-right">
<div class="some-content"></div>
</div>
<div class="left-right">
<div class="some-content"></div>
</div>
<div class="left-right">
<div class="some-content"></div>
</div>
</div>
</div>
#container{
height: 100px;
width: 200px;
}
#data-container{
height: 500px;
width: 200px;
overflow-y: auto;
}
.left-right{
height: 50px;
width: 300px;
overflow-x: auto;
}
After a lot of testing I think I found a solution to what you mean.
Here the green elements move left and right, and the whole red container moves up and down.
#container {
background: blue;
height: 100px;
width: 200px;
overflow-x: hidden;
}
#data-container {
background: red;
height: 500px;
width: 200px;
white-space: nowrap;
overflow: auto;
}
.left-right {
background: green;
overflow-x: auto;
}
.some-content {
width: 300px;
height: 50px;
}
<div id="container">
<div id="data-container">
<div class="left-right">
<div class="some-content">LEFT-RIGHT A</div>
</div>
<div class="left-right">
<div class="some-content">LEFT-RIGHT B</div>
</div>
<div class="left-right">
<div class="some-content">LEFT-RIGHT C</div>
</div>
ONLY UP AND DOWN
</div>
</div>