I have a wrapper container with a fixed height and width, and is set to overflow: scroll. Inside, I have a bunch of other content that is accessible by scrolling around to it.
I also have a zoom-in and zoom-out button. The buttons apply a transform: scale(x) to the content, which seems to work just fine. I've set the transform-origin to be the centre of what's visible in the wrapper by checking the wrapper's scrollTop value.
My issue, however, is that when the content is zoomed in on, it is cut off by the wrapper (expected) but is inaccessible by scrolling (unexpected).
I've created an example of my issue with a JSFiddle, and will also post the code here:
let zoom = 1;
function fnZoom(zoomModifier) {
zoom += zoomModifier;
let scrollTop = document.getElementById("a").scrollTop;
document.getElementById("b").style.transformOrigin = `150px ${scrollTop + 100}px`;
document.getElementById("b").style.transform = `scale(${zoom})`;
}
#a {
margin: 0 auto;
overflow: scroll;
width: 300px;
height: 200px;
border: 3px solid red;
overflow: scroll;
}
#b {
transform: scale(1);
transform-origin: 0 0;
width: 300px;
height: 20000px;
background-color: lightyellow;
}
#c {
margin-top: 100px;
width: 100%;
background-color: skyblue;
}
<html>
<body>
<div id="a">
<div id="b">
Test
<p id="c">
middle
</p>
</div>
</div>
<button onclick="fnZoom(0.1)">zoom-in</button>
<button onclick="fnZoom(-0.1)">zoom-out</button>
</body>
</html>
Notice that if you click on the zoom-in button, it will zoom the content correctly, but the cut-off portion of the content is inaccessible by scrolling.
Is there any way to fix this so that the content can be scrolled to?
A couple things to note:
Cannot use jQuery
Would prefer CSS-based solutions of JavaScript solutions, but will accept either that works
Related
plz help thanks in advance...sorry for bad english ... want a animation effect with bouncing when div1 and div2 goes up and down
I have made main div in which there are 2 div... div1 and div2.
I want to make it like, when someone click on button.
That time div1 should slowly move out of the screen from top side with animation (slowly moving out of the top side screen).
And at the same time div2 should take a place 20px from top of screen.
I have setup almost everything but I'm not able to give it a animation effect no wonder why but transition effect or anything not working on it. I want to do it with JavaScript code if possible I less use jQuery or etc.
I am happy to use another approach, like instead of using margin-top to move div1 out of screen and div2 to top side if you recommend any other css or javascript, that's fine. I just want the animation effect in which slowly div1 and div2 move to top side.
function myFunction1() {
document.getElementById("div1").style.marginTop = "-110px";
document.getElementById("div2").style.marginTop = "20px";
}
function myFunction2() {
document.getElementById("div1").style.marginTop = "0px";
document.getElementById("div2").style.marginTop = "0px";
}
#main {
background-color: grey;
height: 1000px;
width: 100%;
margin: 0;
padding: 0;
}
#div1 {
background-color: red;
height: 100px;
width: 100%;
margin-top: 0px;
position: relative;
}
#div2 {
background-color: green;
height: 100px;
width: 100%;
margin-top: 0px;
position: relative;
}
<div id="main">
<div id="div1"> </div>
<div id="div2"> </div>
<button onclick="myFunction1()">Button 1</button>
<button onclick="myFunction2()">Button 2</button>
</div>
Just add a CSS transition to your elements. You can change the parameters to taste. I believe this is the cleanest and most efficient solution.
EDIT: As per OP's request in the comments, I've shown an example of a transition function which emulates a slight "bounce" effect on the transition using extreme values. You can quickly create your own transition function and test it in real time using online tools (ex: cubic-bezier.com) or the Chrome developer tools (you can click on a transition function for an element you are inspecting to edit the function in real time). Note that this functionality is currently not universally supported (see: Safari Bug 45761)
Transitions on MDN
function myFunction1() {
document.getElementById("div1").style.marginTop = "-110px";
document.getElementById("div2").style.marginTop = "20px";
}
function myFunction2() {
document.getElementById("div1").style.marginTop = "0px";
document.getElementById("div2").style.marginTop = "0px";
}
#main {
background-color: grey;
height: 1000px;
width: 100%;
margin: 0;
padding: 0;
}
/* *** THIS IS NEW *** */
#main div {
-webkit-transition: margin 1s cubic-bezier(1,.7,.49,1.7);
transition: margin 1s cubic-bezier(1,.7,.49,1.7);
}
/* *** END NEW *** */
#div1 {
background-color: red;
height: 100px;
width: 100%;
margin-top: 0px;
position: relative;
}
#div2 {
background-color: green;
height: 100px;
width: 100%;
margin-top: 0px;
position: relative;
}
<div id="main">
<div id="div1"> </div>
<div id="div2"> </div>
<button onclick="myFunction1()">Button 1</button>
<button onclick="myFunction2()">Button 2</button>
</div>
For a small project, I experience a behaviour in Firefox (both mobile and desktop) that I believe is a bug : using chromium I don't have the bug and inspecting the html triggers a repaint and solves the problem.
In an attempt for a responsive design I have a side panel that is absolutely positionned and slides in and out. In this side panel, I am willing to have a fixed element. The fixed position is only specified for bottom, and the fixed element should therefore translate sideways with the containing panel. In firefox the position is however not updated properly, and the fixed element does not translate lateraly. Searching, I came up with a hacky workaround, but this fix is not perfect, and introduces tiny bugs where other browsers didn't have any. I therefore also desigend a test to check whether the browser experiences the bug, so that I only use the hack when necessary. Here is a minimal example derived from my code.
/* Fix to programatically force fixed element repositionning */
var trigger = document.getElementById('trigger');
var container = document.getElementById('container');
var child = document.getElementById('child');
function from_and_back(evt) {
if (container.children.length) {
container.removeChild(child);
setTimeout(function() {
container.appendChild(child);
}, 300);
}
}
trigger.addEventListener('mouseenter', from_and_back);
trigger.addEventListener('mouseleave', from_and_back);
/* Simulate the bug to check whether the browser experiences it */
var bug_status = document.getElementById('bug-status');
bug_status.innerText = (function() {
//create an absolutely positionned element
var abs = document.createElement('div');
abs.style.position = 'relative';
abs.style.left = '0px';
//create a fixed element to put inside
var fix = document.createElement('div');
fix.style.position = 'fixed';
//insert it into the document
abs.appendChild(fix);
document.body.appendChild(abs);
//test
fix.getBoundingClientRect(); /************ this line *************/
abs.style.left = '20px';
var fix_left = fix.getBoundingClientRect().left;
var abs_left = abs.getBoundingClientRect().left;
//remove test elements from the document
document.body.removeChild(abs);
//send the result
return abs_left !== fix_left;
})();
/* Wrapper class to trigger the effect */
.trigger {
width: 220px;
border: 1px solid #000;
display: inline-block;
}
.trigger:hover .container {
left: 200px;
}
/* Absolutely positionned element */
.container {
position: relative;
width: 20px;
height: 20px;
left: 0px;
background: #aaa;
transition: all .25s ease-out;
}
/* Fixed element inside the absolute one */
.child {
position: fixed;
width: 20px;
height: 20px;
background: #aaa;
top: 100px;
}
<!-- Display the bug test result -->
Your browser has the bug : <span id='bug-status'></span>
<br/>
<br/>
<div class="trigger">
<!-- Demonstrate the error without any fix -->
<span>Reference</span>
<br/>
<div class="container">
<div class="child"></div>
</div>
</div>
</div>
<!-- Apply the fix fix -->
<div class="trigger" id="trigger">
<span>Fixed</span>
<br/>
<div class="container" id="container">
<div class="child" id="child"></div>
</div>
</div>
Now the questions :
Obviously my workaround is not fully satisfactory : the smooth transition is lost, and in the example, if the mouse moves fastly in and out of the trigger, the fixed element remains dangling in the middle. Do you have ideas for a better workaround, or design with the same behaviour without the bug ?
In the javascript test, I marked a line. Removing the line makes the test pass on Firefox. I don't get why, but perhaps this could be used to workaround the bug less roughly ?
A workaround which might give the same result you want is to move the .child outside the moving container, and apply the same transformation on trigger:hover, just using margin-left or even transform: translateX(200px) to not mess with the fixed positioning.
(Using transform instead of positioning on the container actually would solve the rendering issue, but sadly it also makes the position:fixed relative to the transformed element instead of the viewport.)
/* Wrapper class to trigger the effect */
.trigger {
width: 220px;
border: 1px solid #000;
display: inline-block;
}
.trigger:hover .container {
left: 200px;
}
.trigger:hover .child {
margin-left: 200px;
}
.container {
position: relative;
width: 20px;
height: 20px;
left: 0px;
background: #aaa;
transition: all .25s ease-out;
}
.child {
position: fixed;
width: 20px;
height: 20px;
background: #aaa;
top: 100px;
margin-left: 0;
transition: all .25s ease-out;
}
<div class="trigger">
<div class="container">
</div>
<div class="child"></div>
</div>
I have two "DIV"s, one on the left and one on the right. The right one has draggable elements and the left one has a droppable container. Both DIV's have the CSS attribute overflow: auto, which is essential in my implementation because I need a scroll to appear in each div when either DIV overflows.
The issue is, when I drag the element in the right DIV, and move it to the left, it disappears after the edge of the DIV.
This is a sample of what I'm trying to do.
<!DOCTYPE html>
<html>
<head>
<title>Practice</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<script>
$(function() {
for (var i = 1; i <= 20; i++) {
$('#right').append($('<div></div>')
.addClass('item')
.html(i));
}
$(".item").draggable({
cursor: "move",
revert: "invalid"
});
$("#bin").droppable({
drop: function(event, ui) {
var mydiv = $(ui.draggable);
$("#bin").html("Dropped");
}
});
});
</script>
<style>
#left {
border: 2px solid black;
position: fixed;
width: 49%;
height: 98%;
overflow: auto;
}
#right {
border: 2px solid black;
position: fixed;
left: 52%;
top: 2%;
width: 46%;
height: 98%;
overflow: auto;
}
#bin {
border: 2px solid black;
position: relative;
left: 12%;
top: 5%;
width: 75%;
height: 75%;
}
.item {
border: 2px solid black;
left: 12%;
top: 5%;
width: 15%;
height: 5%;
}
</style>
</head>
<body>
<div id="left">
<div id="bin">
</div>
</div>
<div id="right">
</div>
</body>
</html>
You need to remove the overflow:auto in your CSS. You will then see the item will be visible when dragging between the divs then.
In order to accomplish the functionality you'd like, you need an outer div wrapping the two container boxes. You'd set an fixed height on the outer div, then use overflow-y:scroll to get your functionality.
You can do as others have suggested, but I've always found the best way to accomplish this is to set the draggable item to position:fixed
see for example:
https://jsfiddle.net/gregborbonus/tzz0927p/1/
For me personally, this allowed a lot more flexibility, but I also did a lot of work with responsive designs and such to make it work right.
I've edited to include overlapping div's. Added a few functions to make it more visible, like random Color, and an on hover and hover out event to make it possible to see and click each box.
https://jsfiddle.net/gregborbonus/tzz0927p/3/
With 100 and added a scroll function to make the scroll smooth. Also added a quick snippet so that the elements would only appear within the containing box.
This is different from your code, it uses 2 containers, rightc for the main container(the one that scrolls) and right for the container of all the elements. The rest is commented in the code.
https://jsfiddle.net/gregborbonus/tzz0927p/13/
so, something I realized was that the elements would still overlap the page on page load.
So, to show this working with an even shorter div and changed to compensate for onload:
https://jsfiddle.net/gregborbonus/tzz0927p/15/
This question already has answers here:
Hide scroll bar, but while still being able to scroll
(42 answers)
Closed 8 years ago.
This is a reference that I used, which explains how to make a div scrollable with its scroll bar hidden. The only difference is that I have nested divs. Check my fiddle
HTML:
<div id="main">
<div id="sub-main">
<div id="content">
<div id="item-container">
<div class="item">a</div>
<div class="item">b</div>
<div class="item">c</div>
</div>
</div>
</div>
</div>
CSS:
#main {
width: 500px;
height: 500px;
}
#sub-main {
width: 500px;
height: 500px;
overflow: hidden;
}
#content {
background-color: red;
width: 500px;
height: 500px;
overflow: auto;
}
#item-container {
width: 1500px;
height: 500px;
}
.item {
width: 500px;
height: 500px;
font-size: 25em;
text-align: center;
float: left;
}
Like above, I have a overflowed horizontal div and I want to hide its scroll bar. I have to make it still scrollable because $.scrollTo() wouldn't work otherwise.
UPDATE:
I have read all the answers, but I still have not resolved my problem and don't know what's causing it. This is the live that's having troubles.
Basically, I am trying to follow this almost exactly the same, but there must be some reason that my website isn't working as expected. There are two problems.
When I set overflow: hidden to a parent container of scrollable items, I cannot scroll (native javascript scroll functions do not work too).
I want to scroll just the overflowed container, not the entire window. This can be done by setting a target in $.localScroll({ target: '#projects-content' }) but nothing scrolls when I set the target. If I don't, scrolling works as long as overflow:hidden is not applied.
Again, any help would be greatly appreciated.
HTML:
<div id="projects"> <!-- start of entire projects page -->
<div id="project-sidebar">
<a href="#project-first">
<div class="sidebar-item sidebar-first">first</div>
</a>
<a href="#project-second">
<div class="sidebar-item sidebar-second">second</div>
</a>
<a href="#">
<div class="sidebar-item sidebar-third">third</div>
</a>
</div>
<div id="project-content"> <!-- this must be the scrollable itmes' container, not the entire window -->
<div id="project-first" class="project-item">
<!-- these items should be scrollable -->
<div class="project-subitem" id="first-sub1">
<a href='#first-sub2' class='next'>next</a>
</div>
<div class='project-subitem' id='first-sub2'>
<a href='#first-sub1' class='prev'>prev</a>
</div>
<!-- end of scrollable items -->
</div>
</div> <!-- end of scroll scroll container -->
</div> <!-- end of entire projects page -->
<script>
// FIXME: when I set target, nothing scrolls.
// But I don't want the entire window to scroll
$('#projects').localScroll({
//target: '#project-content',
hash: false
});
</script>
CSS
#project-content {
width: 80%;
height: 100%;
position: relative;
float: left;
}
#project-sidebar {
float: left;
width: 20%;
height: 100%;
}
.project-item {
width: 300%;
height: 100%;
}
.project-subitem {
height: 100%;
width: 33.33%;
position: relative;
float: left;
}
Update:
After I added overflow:scroll to #project-content, the scrolling works as expected. All I need now is making scroll bars disappear in #project-content. I tried adding overflow:hidden to its parent but had no success. I also tried adding it to html, body, but then the entire document refuses to accept any scrolling functions like scrollTop().
Any help will be greatly appreciated!
Theory :
The technique is to use a parent container that is shorter than the child element with scrollbar. This image shows what I mean :
Practice :
In your case, I suggest using absolute positionning and negative bottom value on #project-content so it overflows it's parent container (#projects) at the bottom.
The point is now what negative value? It should be the same value as the with of a scroll but scrollbars are never the same width according to browsers. So I suggest giving a bigger value : -30pxto be sure it is hidden. You will just need to be carefull that you don't have content to close to the bottom that can be hidden on browesers with thin scrollbars.
This is the CSS you should add to your website :
#projects{
position: relative;
}
#project-content{
position: absolute;
top: 0;
left: 20%;
bottom: -30px;
/* remove:
height: 100%;
position: relative;
float: left;
padding-bottom: -15px
/*
}
scollbars take up around 20px so just make you scrollable div 20px taller and 20px wider and your scrollbars will be hidden:
#content {
background-color: red;
width: 520px;
height: 520px;
overflow: auto;
}
Example
It's kind of cheating but could you hide it behind the #content like this DEMO
#content {
background-color: red;
width: 500px;
height: 480px;
overflow: hidden;
}
#item-container {
width: 1500px;
height: 500px;
overflow: scroll;
}
If you know all containers that can be scrollable, you can hide scrollbar with CSS and a little bit of JS. For webkit-based browsers (safari, google chrome, opera) it will be CSS-only solution to set scrollbar width to 0. For IE, Firefox and other non-webkit browsers you should calculate scrollbar width that will be used as negative margin-right for you scrollable content.
To do so you should wrap your content into div with overflow-y:scroll to always show vertical scrollbar and hide this scrollbar with margin-right:-17px and parent overflow:hidden. Example is here. No need to set fixed width, nor height.
This is the way that used in jQuery Scrollbar. Hiding horizontal scrollbar is more complicated and requires to handle content changes to recalculate container height.
I basicly add padding:0 1em 1em 0; to the element where it is supposed to be hidden , this hides both scrollbars if parent has overflow: hidden. tune padding-bottom or only padding-right, if it is to hide only one of them.
1em is average width of scroll bars in most browsers :
http://jsfiddle.net/5GCsJ/912/
The solution to make the content itself with horizontal scroll.
Just increase the height of #main, and #content.
#main {
width: 500px;
height: 520px;
}
#sub-main {
overflow: hidden;
}
#content {
background-color: red;
width: 500px;
height: 520px;
overflow: auto;
}
#item-container {
width: 1500px;
height: 500px;
overflow: hidden;
}
.item {
width: 500px;
height: 500px;
font-size: 25em;
text-align: center;
float: left;
}
Use a script to create custom scrollbars.
http://manos.malihu.gr/jquery-custom-content-scroller/
Then use CSS(or modify script or change script config) to hide the custom scrollbars.
I did this crudely using jQuery and your example
Check this fiddle:
I simply detected the direction of the scroll-wheel and pushed the horiz-scroll bar with jQuery
$(document).ready(function(){
$('#content').bind('mousewheel', function(e){
var curScroll = $("#content").scrollLeft();
if(e.originalEvent.wheelDelta > 0) {
$("#content").scrollLeft(curScroll-500);
} else {
$("#content").scrollLeft(curScroll+500);
}
});
});
It is "crude" because I hard-coded some values like the 500px amount to scroll, you could write some more javascript to detect dynamically how much to scroll. Plus I don't know if the wheelDelta value will be +120 for up and -120 for down, for you and other users.
Also note that the scrolLeft() can be animated.. for smoother transitions.
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>