CSS Transform-Origin Center Overflow Scroll Not Full Width - css

I've searched and can't find a solution or even ideas on this.
We have a child element inside a scrollable parent. We transform the child to scale larger. When the transform-origin is top left the overflow: scroll works correctly and you can scroll the entire thing. When the transform-origin is center top it scales but the overflow: scroll only starts from the mid-point and there's no way to scroll to the first half of the child.
Here's a simple example showing how it works:
.wrapper {
width: 200px;
height: 200px;
padding: 20px;
border: 1px solid #888;
overflow: auto;
position: relative;
border-radius: 0.001px;
}
.scale {
border-radius: 0.001px;
position: relative;
background-color: #ffff88;
transform: scale(1);
transform-origin: center top;
transition: all 0.5s ease-in-out;
}
.scale--2{
transform-origin: top left;
}
.scale {
transform: scale(4);
}
<div class="wrapper">
<div class="scale">First text - I'm scaling center top</div>
</div>
<div class="wrapper">
<div class="scale scale--2">First text - I'm scaling top left</div>
</div>
Any thoughts or hacks at this point would be awesome.

CSS3 transform has nothing to do with your issue ← you can replicate the same by using a simple left: -100px; on a standard (wider) child element.
(depending on text-direction) If you offset left an element out of a parent boundary - the browser will not paint for you the scrollbars - such element will simply be eaten by the overflow-scroll parent edge.
In the case the child is wider - the browser will paint UI scrollbars
But if you move that wide child to negative left... read again point 1.
the case can be expressed as scrollWidth = childWidth - eatenLeftPortion
Therefore
Browser paints the UI scrollbars
CSS cannot move scrollbars.
The browser will not paint scrollbars if an element is pushed negative top or left (in text-direction ltr; right for rtl)
solution
scale your element using transform-origin: top left; (your second example)
(now the scrollbar is in it's full scrollable state since there's no left-eaten portions)
using JavaScript animate or move scrollLeft by (parentScrollWidth -
parentWidth) / 2
var parent = document.querySelector('.wrapper');
parent.scrollLeft = (parent.scrollWidth - parent.clientWidth) / 2 ;
/*QuickReset*/ *{margin:0;box-sizing:border-box;} html,body{height:100%;font:14px/1.4 sans-serif;}
.wrapper {
position: relative;
overflow: auto;
width: 200px;
height: 140px;
border: 1px solid #888;
}
.scale {
position: relative;
background-color: #ffff88;
transform-origin: left top;
transform: scale(4);
}
<div class="wrapper">
<div class="scale">I'm scaling center top</div>
</div>

For centering a child element within a parent div with parent scrollbars reflecting centered position of child element, I use the following code handled by a range input:
var scaleValue = $('#mySliderRange').val();
// Handles child scaling
child.css({'width':scaleValue+'%','height':scaleValue+'%'});
// Keeps child in vertical middle position
parent.scrollTop((child.height() - parent.height())/2);
// Keeps child in horizontal middle position
parent.scrollLeft((child.width() - parent.width())/2);
The above setup is a substitution to the issue of unreliable parent scrollbar positioning when dealing with CSS3 centered scaling. Hope this helps.

Related

Issue with positioning and sticky scroll of absolute div

I have two divs side by side, the first on about 60% of the page is positioned as "relative" on the left, the second is placed as "absolute" on the right as it is the only way I managed to place them side by side.
The div on the right is only about 10% (measures about 1 view port height) of the full height of the webpage. The div on the left which measures roughly 10 viewport heights defines the full height of the webpage. Hence, I would like to be able to have the right div slide down as the user scrolls down so as to not leave a blank space on the right of the left div below the right div.
The issue is that I can't manage to have the right div set as sticky and scroll down and still keep them right next to eachother at the top when the page first loads. The sticky div will be on top whhile the left div starts just when the sticky div finishes. Basically it behaves the same as if I set both of them relative but I need the right divv to behave as an absolute div before it becomes sticky to preserve the positioning.
With absolute positioning:
.mainbodyfx {
width: 60vw;
padding-left: 10vw;
right: 40vw;
margin-left: 0;
margin-right: 0;
height: 10vh;
}
.floatingfxbuy {
position: absolute;
background-color: transparent;
width: 20vw;
left: 75%;
height:1vh;
}
<div> Content of full height and width slider </div>
<div class=floatingfxbuy> Right div that needs to slide down with scroll </div>
<div class="mainbodyfx"> Left div that defines the height of the whole webpage</div>
With sticky positioning:
.mainbodyfx {
width: 60vw;
padding-left: 10vw;
right: 40vw;
margin-left: 0;
margin-right: 0;
height: 10vh;
}
.floatingfxbuy {
position: sticky;
background-color: transparent;
width: 20vw;
left: 75%;
height:1vh;
}
<div> Content of full height and width slider </div>
<div class=floatingfxbuy> Right div that needs to slide down with scroll </div>
<div class="mainbodyfx"> Left div that defines the height of the whole webpage</div>
So, it's hard to tell exactly what you're asking for but I think I'm close to what you're asking for. Essentially if you want a floating side div you need to treat it as completely separate from the other div. Really as far as the css and html goes the .floatingfxbuy div is separate from the entire page.
If you want the floating div to be absolute positioned until you scroll to a certain height you need to use JavaScript to change the position to fixed for the div when the window scrolls to a certain point.
You also need to have the z-index slightly higher on the floating div so that it doesn't interact with any elements "underneath" it.
Here is a quick example I threw together. Sorry about the terrible colors.
$(document).ready(function() { // at document ready run this function
var $window = $(window); // local variable to window
$window.on('scroll resize', function() { // on window scroll or resize run this function
if ($window.scrollTop() > 50) { // if the top of the window is lower than 50px then add the fix class to the .floating-side-div
$('.floating-side-div').addClass('fix');
} else { // if the top of the window is heigher than 100px remove the fix class
$('.floating-side-div').removeClass('fix');
}
});
});
body {
margin: 0;
/* get rid of some default body styles */
}
.page-container {
min-height: 200vh;
/* set height of page so we can scroll to test */
width: 100%;
background-color: green;
}
.content-div {
width: 60vw;
/* width you suggested */
height: 50vh;
/* random height for content */
margin-left: 10vw;
/* some left margin you want */
background-color: red;
}
.floating-side-div {
height: 10vh;
/* 10% viewport height like you want */
width: 20vw;
/* width you have in your css */
background-color: blue;
position: absolute;
/* to start we want absolute position */
right: 0;
/* put it at the right of the page */
top: 0;
/* put it all the way at the top. you can change this if you want */
z-index: 99;
/* increase z-index so we're over top of the other elements on the page and don't distort the page when scrolling */
}
.floating-side-div.fix {
position: fixed;
/* change from absolute to fix so we 'fix' the div to a spot in the viewport. in this example top: 0, right: 0; */
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="page-container">
<!-- our page container -->
<div class="content-div"></div>
<!-- the content div(your .mainbodyfx) -->
<div class="floating-side-div"></div>
<!-- the floating div(your .floatingfxbuy) -->
</div>

CSS Item in center of page pushed up when virtual keyboard is visible

I have the following style for a div which is positioned in the center of the page
<div class="myStyle">Hi All...</div>
CSS Code:
<style>
.myStyle {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
when the virtual keyboard though opens up, the div is being pushed up. I don't understand why though. Any suggestions ?
This is because your viewport (or the element's closest relative positioned parent) is shrinking vertically. If you don't want it to move, you'll have to make sure the closest parent with a relative position has a fixed height.
Here's an example, the second div will move based on the height of the window (open the snippet Full Screen with Dev Tools opened)
.row {
width: 100vw;
}
.col {
width: 50%;
float: left;
position: relative;
background: #eee;
}
.col > div {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
width: 100%;
background: #0095ee;
color: #fff;
}
<div class="row">
<div class="col" style="height: 200px;"><div>My Y center is always 100px;</div></div>
<div class="col" style="height: 100vh;"><div>My Y xenter varies with Devtools/etc.</div></div>
</div>
It will adjust to top 50% from viewport. Try to fix some height to that div and give css like below. Odd effect will be reduced. For eg if height of the popup is 400px and width is 600px(Width you can give in percentage as well)
.div {
width:600px;
height:400px;
position:fixed;
margin : auto;
top:0;
bottom:0;
left:0;
right:0;
}
But if you do not want to push div at all. Then you have to mention top in pixels. To make it work in all devices, you might have to use javascript for that. Like in javascript get the height of viewport, calculate the top you want specify based on viewport height. Apply calculated top in pixels.
For eg if top you want to specify as 50%. Then pseudo javascript code is below.
var divHeight = document.height;
var desiredTop = viewportHeight/2;
div.style.top = desiredTop;
But disadvantage of giving fixed top is there will be chance that div gets hidden behind the keyboard.

CSS - Column aligned to bottom of page but grows with scrolling content.

http://jsfiddle.net/yLhh3/
I have three columns in a deadly simple CSS layout. They look perfect until content is added to one of them thus forcing the page to scroll (scroll down on the fiddle).
All I want is for the red boxes to ALWAYS go to the bottom of the page (not the window / screen, the page). How can this be accomplished with CSS?
.column
{
background-color: red;
width: 400px;
/* Page height minus header */
min-height: calc(100% - 192px);
/* Align to bottom of the page */
position: absolute;
top: 192px;
}
/* Half the page width minus (1.5 columns + offset between columns) */
.left { left: calc(50% - 630px); }
.right { right: calc(50% - 630px); }
/* Half the page width minus 0.5 columns */
.center { left: calc(50% - 200px); }
There has always been issues and questions about this and there are many ways to go about it, but the easiest, since your using absolute positioning, it to wrap the "column" divs inside the "center" div.
<div class="column center">
<div class="column right"></div>
<div class="column left"></div>
</div>
This allows the left and right divs to strech to 100% of the parent, the center. Some minor changes to the css, as you can see in the fiddle, like height: 100% and top: 0 for the contained columns since the parent top is considered 0 for the children.
jsfiddle
I hope I understand what you are trying to achieve.
I've used overflow: scroll; so you would not lose the content (You can set it to only Y if you want or hidden).
I've also used height since with min-height the overflow didn't triggered
.column
{
background-color: red;
width: 400px;
/* Page height minus header */
height: calc(100% - 192px);
/* Align to bottom of the page */
position: absolute;
top: 192px;
overflow: scroll;
}

Centering divs on top of an image

For some reason, I can't get this to work:
Website
(The red and green boxes will be removed once they're properly positioned.)
Thanks for the help.
The overall concept of centering something in css is quite simple. First you need a relative positioned container. The child element to be centered must have a fixed width and height and be absolute positioned at 50% from the top and 50% from the left, and both top and left margins must be negative half of the width and height respectively. In other words:
<div id="container">
<img src="" alt=""/>
<div class="box"></div>
</div>
.
#container { position: relative; }
img { dispaly: block; } /* It fills the container */
#box {
position: absolute;
width: 300px; /* Fixed */
height 150px; /* Fixed */
top: 50%;
left: 50%;
margin-top: -75px; /* 300/2 */
margin-left: -150px; /* 150/2 */
}
As suggested, you can do this with CSS positioning tho for what you appear to be trying to do, you might be better off using an image map
http://www.w3schools.com/tags/tag_map.asp
This allows you to set certain regions of an image as a link.
Try to set the following properties along with position
top:0;
left:0;
you can also set top or left property in order to make the boxes visible at the center
and if you want that your boxes will remain inside the center div then make the div with id splash to position: relative
it will help in solving your issue

How do I centre absolutely positioned content of unknown width?

Before someone asks me why the hell I would want to do this let me come straight out and tell you. That way one of you clever peeps out there can tell me a far better way...
I'm making a viewer for paintings which should stretch to fill the page, well 90% of the height of the screen to be precise. I want to fade the paintings in one over the other and want to center each of them in the middle of the screen.
To fade the paintings in over each other I need to position them 'absolute' to stop them from stacking. Here's where the trouble comes. Ever since I've set them to absolute, every method I use to center the containing div hasn't worked.
Part of the problem is that I'm not setting any width for the paintings as I want them to dynamically size themselves to fill 90% of the user's screen.
I've found a hundreds of methods for centering absolute content and believe I might need to shrink wrap the containing div. However I've not had any success as of yet.
HTML-
<div id="viewer_div">
<img src="" id="first" />
<img id="second" class="hidden"/>
</div>
Style Sheet
#viewer_div {
width:1264px;
}
img {
height:90%;
display:block;
margin-left: auto;
margin-right:auto;
}
The above gives me the desired effect, but doesn't allow me to position the images absolute. Can anyone suggest a way of centering the images but also allows me to fade one over the other?
Pushing the element left by 50% of its width and then translating it horizontally by 50% has worked for me.
.element {
position: absolute;
left: 50%;
transform: translateX(-50%);
}
I found the concept in the following link, and then I translated to fit my horizontal align needs: https://gist.github.com/colintoh/62c78414443e758c9991#file-douchebag-vertical-align-css
Either use JavaScript to calculate the width and move it,
use a CSS hack to move the element right and left by 50%,
or don't absolutely position it.
This answer is incredibly short, but it is to the point. If you require something to be centralised (meaning you would like the browser to determine where the centre point is, and position it there), then you can't use absolute positioning - because that takes away control from the browser.
To fade the paintings in over each other I need to position them
'absolute' to stop them from stacking.
This is where your problem lies. You have assumed that you need absolute positioning for the wrong reason.
If you are experiencing problems placing elements on top of each other, wrap the images in an absolutely positioned container which is 100% width and has text-align: center
If you do feel that absolute positioning is necessary, the following hack can be used to achieve your desired results:
div {
position: absolute;
/* move the element half way across the screen */
left: 50%;
/* allow the width to be calculated dynamically */
width: auto;
/* then move the element back again using a transform */
transform: translateX(-50%);
}
Obviously the above hack has a terrible code smell, but it works on some browsers. Be aware: this hack is not necessarily obvious to other developers, or other browsers (especially IE or mobile).
To go off of Samec's answer, you can also use this to center an absolute position element vertically and horizontally of unknown dimensions:
#viewer_div {
position: relative;
}
#viewer_div img {
position: absolute;
left: 50%;
top: 0%;
transform: translate(-50%, 50%);
}
Centering div with position: absolute and width: unknown:
HTML:
<div class="center">
<span></span>
<div>
content...
</div>
</div>
CSS:
.center{
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: grid;
grid-template-columns: auto auto;
/* if you need the overflow */
overflow: auto;
}
You can use this solution even if the content is wider than the screen width, and don't need to transform: translate (which can blur elements)
How it works:
Grid will insert a span before the first auto, and insert a div right before the second auto, and you get:
span(0px) - auto - div(...px) - auto
auto will be equal to each other.
Same for vertical centering, but write grid-template-rows instead of a grid-template-columns
2021
A modern approach to absolutely centered content with grid and inset
The inset CSS property is a shorthand that corresponds to the top, right, bottom, and/or left. MDN
#viewer_div {
display: grid;
place-items: center;
position: absolute;
inset: auto 0;
}
*,
::after,
::before {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
}
body {
width: 100vw;
height: 100vh;
background-color: hsl(201, 27%, 10%);
position: relative;
}
#viewer_div {
display: grid;
place-items: center;
position: absolute;
inset: auto 0;
background-color: hsl(197, 7%, 21%);
color: white;
}
<div id="viewer_div">
<h1>Title 2021</h1>
<img src="https://via.placeholder.com/180x100.png/09f/fff" id="first" />
</div>

Resources