Right now the toggle will open content downwards but some of it is cut off by the viewport. How can I make it so that the content from the toggle always fits the viewport by pushing up the content above it?
$(document).ready(function() {
$(".content").hide();
$(".toggle").on("click", function(e) {
$(this).next('.content').slideToggle(200);
});
});
An image of the problem:
EDIT
I tried adding the code suggested by Aleks G:
$(document).ready(function(){
$(".content").hide();
$(".toggle").on("click", function(e){
$(this).next('.content').slideToggle(200, function() {
if($(this).position().top + $(this).height() > $(this).parent().innerHeight()) {
$(this).parent().scrollTop($(this).position().top - 100);
}
});
});
});
EDIT 2
New JSFiddle: /
Right now the toggle will open content downwards but some of it is cut off by the viewport. How can I make it so that the content from the toggle always fits the viewport by pushing up the content above it?
$(document).ready(function() {
$(".content").hide();
$(".toggle").on("click", function(e) {
$(this).next('.content').slideToggle(200);
});
});
An image of the problem:
EDIT
I tried adding the code suggested by Aleks G:
$(document).ready(function(){
$(".content").hide();
$(".toggle").on("click", function(e){
$(this).next('.content').slideToggle(200, function() {
if($(this).position().top + $(this).height() > $(this).parent().innerHeight()) {
$(this).parent().scrollTop($(this).position().top - 100);
}
});
});
});
EDIT 2
New JSFiddle: http://jsfiddle/Dar_T/2h2wjp2L/
Share Improve this question edited Aug 14, 2014 at 12:26 Pieter VDE 2,2354 gold badges26 silver badges45 bronze badges asked Aug 5, 2014 at 12:43 user2252219user2252219 8653 gold badges17 silver badges42 bronze badges 7- Possible duplicate of stackoverflow./questions/4574501/… – soktinpk Commented Aug 5, 2014 at 12:45
- I was looking at that. However, I still want the content from the toggle to move down not up. I just want it to move so that it fits the viewport. – user2252219 Commented Aug 5, 2014 at 12:56
- The fiddle does not work – Pablo Matias Gomez Commented Aug 7, 2014 at 14:31
- @PabloMatíasGomez I updated OP with the fiddle. :) – user2252219 Commented Aug 8, 2014 at 20:07
- What happens if the viewpoint isn't high enough for the picture and the text; does the text overlay on top of the picture? – Lloyd Banks Commented Aug 9, 2014 at 2:58
7 Answers
Reset to default 2What you need is to add a "plete" parameter to your slideToggle
call. In it, simply check the height of the opened content and, if it extends beyond the inner height of your viewport, then scroll your viewport to the top of the content.
Here's the jsFiddle demonstrating the idea.
In that example, my viewport is a fixed max-height div. I toggle a large block of text. In the pletion function, I check the height of the text and, if necessary, scroll the parent div.
Here is the relevant javascript:
$(document).ready(function(){
$('#toggler').on("click", function() {
$('#content').slideToggle("slow", function() {
if($(this).position().top + $(this).height() > $(this).parent().innerHeight()) {
$(this).parent().scrollTop($(this).position().top - 10);
}
});
});
});
Note the extra - 10
in the scroll position - for some reason when testing, it always scrolled 10 pixels beyond the start of the div, so this is a dirty hack to scroll to the right position.
EDIT: I updated the javascript slightly so that it positions the newly opened div 100px from the bottom of the viewport instead of brining it to the top of the viewport. You can play with the - 100
part to modify the positioning. For some reason I can't get jsfiddle to save what I created and give me the unique url - something is not working correctly there, therefore here's my full code.
HTML:
<div class="viewport">
<button id="toggler">More info</button>
<img src="http://www.random/analysis/randbitmap-rdo-section.png" />
<div id="content">Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. Lorem Ipsum es from sections 1.10.32 and 1.10.33 of "de Finibus Bonorum et Malorum" (The Extremes of Good and Evil) by Cicero, written in 45 BC. This book is a treatise on the theory of ethics, very popular during the Renaissance. The first line of Lorem Ipsum, "Lorem ipsum dolor sit amet..", es from a line in section 1.10.32. The standard chunk of Lorem Ipsum used since the 1500s is reproduced below for those interested. Sections 1.10.32 and 1.10.33 from "de Finibus Bonorum et Malorum" by Cicero are also reproduced in their exact original form, acpanied by English versions from the 1914 translation by H. Rackham.</div>
</div>
CSS:
.viewport {
max-height: 300px;
border: solid 1px darkGrey;
padding: 10px;
overflow: auto;
}
div#content {
display: none;
}
Javascript:
$(document).ready(function () {
$('#toggler').on("click", function () {
$('#content').slideToggle("slow", function () {
if ($(this).position().top + $(this).height() > $(this).parent().innerHeight()) {
//$(this).parent().scrollTop($(this).position().top - 10);
$(this).parent().scrollTop($(this).position().top - $(this).parent().innerHeight() + 100)
}
});
});
});
If you want the window to scroll to the toggled text you can do the following:
$(document).ready(function () {
$('.toggle').on("click", function () {
$('.content').slideToggle("slow", function () {
$(window).scrollTop($(this).offset().top + $(this).height());
});
});
});
What this code does is that it scrolls the window to the bottom of the toggled text in the button click event.
And here is a fiddle.
Hope this helps.
You could create the effect by yourself.
Change the javascript like this:
$(document).ready(function(){
$(".box").on("click", '.toggle', function(){
$(this).prev('.content').toggleClass('visible');
});
});
You will also need to update the layout.
<div class="box">
<div class="content">content...</div>
<div class="toggle">More information</div>
<div class="content">content...</div>
<div class="toggle">More information</div>
</div>
CSS should be as following:
.content {
max-height: 0px;
overflow: hidden;
-webkit-transition: all 1s ease;
}
.content.visible {
max-height: 500px;
}
Fiddle
Is this what you mean? http://jsfiddle/2r89M/1/ wrap your html with
<div class="wrapper">
<div class="container">
<p>aaaaaaaa</p><!-- this is the content above -->
<!-- Your code here -->
</div>
</div>
Then add the following css:
.wrapper {
height: 300px;
position: relative;
}
.container {
position: absolute;
bottom: 0px;
}
this can be easily achieved by detecting the bottom position of the opened element, if the opened element after toggle is out of viewport then we can find the pixel amount of outer element and scroll the window same amount to bottom.
$('.toggle').on("click", function () {
var elem = $(this);
elem.next().slideToggle(500, function () {
var topp = elem.next().offset().top;
var heghtp = elem.next().height();
var bottomp = topp+heghtp;
var wpos = WH+WS;
if(bottomp>wpos){
var toSlideUp = bottomp-wpos;
var Pos = WS+toSlideUp;
$('html,body').animate({scrollTop:Pos},500);
}
});
});
I have implemented the same functionality here, please see the jsfiddle
You can manipulate the window's scroll top and animate it to bring the toggled content upward as follows:
$(document).ready(function () {
$('.toggle').on("click", function () {
$(this).next('.content').slideToggle("slow", function () {
var offset = $(this).offset().top;
$("html, body").animate({
scrollTop: offset
});
});
});
});
side note: this has the disadvantage of having to wait till the animation is plete
Demo
If you want both the animations to happen simultaneously, you can use css transition instead as follows:
CSS:
.content {
/*existing styles*/
max-height:1000px; /*large value*/
-webkit-transition: max-height 1s ease-in-out;
-ms-transition: max-height 1s ease-in-out;
-moz-transition: max-height 1s ease-in-out;
transition: max-height .5s ease-in-out;
}
.hidden {
overflow:hidden;
max-height:0 !important;
}
JS:
$('.toggle').on("click", function () {
var $content = $(this).next('.content');
$content.toggleClass("hidden");
if (!$content.hasClass("hidden")) {
var offset = $content.offset().top;
$("html, body").animate({
scrollTop: offset
}, 500);
}
});
Demo
It takes bottom margin in account and looks quite clean.
$.fn.notOnScreenHeight = function(){
var viewportBottom = $(window).scrollTop() + $(window).height();
var contentBottom = this.offset().top + this.height();
return contentBottom - viewportBottom;
};
$(document).ready(function () {
var margin = 100;
$('.toggle').on("click", function () {
$(this).next('.content').slideToggle("slow",function () {
var notOnScreen = $(this).notOnScreenHeight();
if (notOnScreen > 0 ) {
var scrollTo = $(window).scrollTop() + notOnScreen + margin;
$("html, body").animate({scrollTop: scrollTo}, 'slow');
}
});
});
});
And here is fiddle