jQuery copy height of the closest div - javascript

I am using a jQuery script (below) to get a height of one div and apply it to the one next to it. It works absolutely fine, but it gets wrong if I have another row with the same .app-screenshot class inside, which has a different height.
How can I make .app-screenshot-description class get the height only of the closest .app-screenshot class height?
function getImgHeight() {
var divHeight = $('.app-screenshot').height();
$('.app-screenshot-description').css('height', divHeight+'px');
}
<div class="row">
<div class="app-screenshot">This divs height is 690px</div>
<div class="app-screenshot-description">Second div</div>
</div>
<div class="row">
<div class="app-screenshot">This divs height is 540px</div>
<div class="app-screenshot-description">Second div</div>
</div>

Assuming your html structure is following this pattern
<div class="row">
<div class="app-screenshot"></div>
<div class="app-screenshot-description"></div>
</div>
You can try something like this.
$('.row').each(function(){
var divHeight = $(this).find('.app-screenshot').height();
$(this).find('.app-screenshot-description').css('height', divHeight+'px');
});
You can use closest as well as mentioned in the comment, but if heights are different for each div, you still need to loop over them using each

Search for the divs that are with common Y coordinate:
function getImgHeight() {
$('.app-screenshot').each(function(){
var divHeight = $(this).height();
var divPosition = $(this).offset().top;
$('.app-screenshot-description').each(function(){
if($(this).offset().top == divPosition)
{
/*console.log($(this).offset().top);*/
$(this).css('height', divHeight+'px');
}
});
});
}

You didn't say when your function is supposed to run, but if you loop over the rows, it can work:
$(".row").each(function(index, row){
$(row).find(".app-screenshot-description").css("height", $(row).find(".app-screenshot").css("height"));
});
.row { border:1px solid black;}
.row > div { border:1px dashed red; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="row">
<div class="app-screenshot" style="height:100px">This divs height is 100px</div>
<div class="app-screenshot-description">Second div</div>
</div>
<div class="row">
<div class="app-screenshot" style="height:25px">This divs height is 25px</div>
<div class="app-screenshot-description">Second div</div>
</div>

While you have, as I write this answer, already accepted another answer to your question, I thought I'd take a moment to offer a further answer, which hopefully provides some further alternatives that may may be of use to you. Particularly since the solutions I offer here require no JavaScript to use (although I do use jQuery to demonstrate the functionality of those solutions).
There are three obvious approaches to take that would allow your desired functionality in pure CSS; in this answer I'll go through those options in order of (personal) preference.
1: flexbox.
This approach takes advantage of the fact that flexbox sizes its child items to be the same cross-axis dimension (if the contents are arranged in a row then the cross-axis dimension would be the height, and if arranged in a column the cross-axis dimension would be width).
// This is purely to demonstrate that both elements take
// the same height (that of the 'tallest' sibling.
// binding the anonymous function of the on() method as
// the event-handler for the 'click' event:
$('#resizeHeight').on('click', function() {
// selecting all elements matching the selector,
// and using the css() method's anonymous function
// to style each '.app-screenshot' element
// independently:
$('.app-screenshot').css('height', function() {
// generating a random height up to a maximum of 500px:
let newHeight = Math.floor(Math.random() * 500);
// setting the height of the current element:
this.style.height = newHeight + 'px';
// setting the text of the current element:
this.textContent = newHeight;
});
// triggering the click event on page-load in order
// the elements have a randomly-assigned size on
// page-load:
}).click();
body {
padding-top: 3em;
}
#control {
position: fixed;
top: 0;
left: 0;
right: 0;
height: 2.5em;
text-align: center;
}
.row {
/* setting the display to use the
flexbox layout: */
display: flex;
margin-bottom: 1em;
}
.row>div {
/* setting the flex-grow and flex-shrink
to be 1, and the flex-basis to be auto: */
flex: 1 1 auto;
}
/* Everything below is either for aesthetics
or simple visibility: */
.app-screenshot {
background-color: fuchsia;
}
.app-screenshot-description {
background-color: silver;
}
.app-screenshot::before {
content: "This element's height is: ";
}
.app-screenshot::after {
content: 'px.';
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="control">
<button id="resizeHeight">Randomise height of '.app-screenshot' elements</button>
</div>
<div class="row">
<div class="app-screenshot"></div>
<div class="app-screenshot-description">Second div</div>
</div>
<div class="row">
<div class="app-screenshot"></div>
<div class="app-screenshot-description">Second div</div>
</div>
2. CSS grids.
// This is purely to demonstrate that both elements take
// the same height (that of the 'tallest' sibling.
// binding the anonymous function of the on() method as
// the event-handler for the 'click' event:
$('#resizeHeight').on('click', function() {
// selecting all elements matching the selector,
// and using the css() method's anonymous function
// to style each '.app-screenshot' element
// independently:
$('.app-screenshot').css('height', function() {
// generating a random height up to a maximum of 500px:
let newHeight = Math.floor(Math.random() * 500);
// setting the height of the current element:
this.style.height = newHeight + 'px';
// setting the text of the current element:
this.textContent = newHeight;
});
// triggering the click event on page-load in order
// the elements have a randomly-assigned size on
// page-load:
}).click();
body {
/* Setting the display to use CSS grid layout: */
display: grid;
/* specifying the number of rows, to:
row 1: 3em high,
row 2: min-content,
row 3: min-content.
'min-content' directs the row to be the
smallest practicable size that will still
fully contain the content of the elements
in that row, and because the elements take
up the whole of the allocated space those
elements are of equal height: */
grid-template-rows: 3em min-content min-content;
}
.row {
/* setting the display of the .row elements
to also use grid layout: */
display: grid;
/* setting both columns to be 1 fractional unit
therefore both columns will be the same size;
this can, of course, be adjusted to taste
using any valid CSS grid length unit: */
grid-template-columns: 1fr 1fr;
margin-bottom: 1em;
}
.app-screenshot {
/* Assigning the .app-screenshot element(s) to
be positioned in the first column of its
parent: */
grid-column: 1;
background-color: fuchsia;
}
.app-screenshot-description {
/* Assigning the .app-screenshot-description
element(s) to be positioned in the second
column of its parent: */
grid-column: 2;
background-color: silver;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="control">
<button id="resizeHeight">Randomise height of '.app-screenshot' elements</button>
</div>
<div class="row">
<div class="app-screenshot"></div>
<div class="app-screenshot-description">Second div</div>
</div>
<div class="row">
<div class="app-screenshot"></div>
<div class="app-screenshot-description">Second div</div>
</div>
3. CSS tables.
Ideally this would not be used since – and this is a purely personal opinion – it feels too close to using a <table> element for layout reasons, and while we're not using a <table> element we are using this for, purely, layout reasons. Which still feels dirty to me. It is, though, an option that could be used.
While I would tend to avoid this solution it does have the potential advantage of simplicity, despite the associated 'smell,' and takes advantage of a table-cell's parent table-row being defined by the 'tallest' of its descendants.
// This is purely to demonstrate that both elements take
// the same height (that of the 'tallest' sibling.
// binding the anonymous function of the on() method as
// the event-handler for the 'click' event:
$('#resizeHeight').on('click', function() {
// selecting all elements matching the selector,
// and using the css() method's anonymous function
// to style each '.app-screenshot' element
// independently:
$('.app-screenshot').css('height', function() {
// generating a random height up to a maximum of 500px:
let newHeight = Math.floor(Math.random() * 500);
// setting the height of the current element:
this.style.height = newHeight + 'px';
// setting the text of the current element:
this.textContent = newHeight;
});
// triggering the click event on page-load in order
// the elements have a randomly-assigned size on
// page-load:
}).click();
.row {
/* forcing the '.row' element(s) to display
as a table-row: */
display: table-row;
}
.app-screenshot,
.app-screenshot-description {
/* forcing the selected elements to display
as table-cells: */
display: table-cell;
width: 50vw;
/* emulating the margin-bottom of previous
demos in this answer: */
border-bottom: 1em solid #fff;
}
.app-screenshot {
background-color: fuchsia;
}
.app-screenshot-description {
background-color: silver;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="control">
<button id="resizeHeight">Randomise height of '.app-screenshot' elements</button>
</div>
<div class="row">
<div class="app-screenshot"></div>
<div class="app-screenshot-description">Second div</div>
</div>
<div class="row">
<div class="app-screenshot"></div>
<div class="app-screenshot-description">Second div</div>
</div>
Please note that while I've used jQuery to allow the .app-screenshot elements to be resized neither that jQuery, nor any JavaSCript at all, is necessary to implement these posted solutions, it was used purely to demonstrate the functionality of the solutions.

Related

Making text appear on hover changes div height

I am building a site and one of the components requires different text to be displayed in the same spot when you hover over different blocks. I am using jQuery to accomplish this and changing the html, however I am noticing since the text is different sizes it pushes down the div to allocate more room for the text.
Is it possible to keep the text transparent or something so the colour and html is changed at the same time, to give the illusion it is popping in?
Please see code below:
$(".stats-text-1").hover(
function() {
$(".stats-text").html(
"Our client’s monetary milestones are driven by our social tactics and digital marketing."
);
},
function() {
$(".stats-text").html(" ");
}
);
$(".stats-text-2").hover(
function() {
$(".stats-text").html(
"Our experience is from more than just a couple of wins - it’s from learning through years of wins and losses."
);
},
function() {
$(".stats-text").html(" ");
}
);
$(".stats-text-3").hover(
function() {
$(".stats-text").html(
"Our clients currently see a minimum average of 5.4 times return on ad spend."
);
},
function() {
$(".stats-text").html(" ");
}
);
.stats-1 {
font-size: 12vw;
font-weight: bold;
color: rgba(255, 255, 255, 0.83);
}
.stats-2 {
font-size: 2vw;
font-weight: bold;
color: #f2f2f2;
}
.stats-3 {
font-size: 2vw;
color: rgba(255, 255, 255, 0.6);
}
.stats-text {
padding-top: 1rem;
font-size: 2vw;
text-align: left;
color: #fff6f4;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="row">
<div class="col-1"> </div>
<div class="col-11 card-2-title">BEEN THERE, DONE THAT.</div>
<div class="card-2-title-mobile">BEEN THERE, DONE THAT.</div>
</div>
</div>
<div class="row stats-border">
<div class="col-1"> </div>
<div class="col-3 stats stats-text-1">
<h1 class="stats-1" style="text-align: center">11</h1>
<h2 class="stats-2" style="text-align: center">Million</h2>
<h3 class="stats-3" style="text-align: center">
Revenue Generated
</h3>
</div>
<div class="col-spec24"> </div>
<div class="col-3 stats stats-text-2">
<h1 class="stats-1" style="text-align: center">9</h1>
<h2 class="stats-2" style="text-align: center">Years</h2>
<h3 class="stats-3" style="text-align: center">
In The Making
</h3>
</div>
<div class="col-spec24"> </div>
<div class="col-3 stats stats-text-3">
<h1 class="stats-1" style="text-align: center">6</h1>
<h2 class="stats-2" style="text-align: center">Times</h2>
<h3 class="stats-3" style="text-align: center">
Return On Ad Spend
</h3>
</div>
<div class="col-1"> </div>
</div>
<div class="card-2-desktop" style="padding-bottom: 15vw">
<div class="row">
<div class="col-1"> </div>
<div class="col-7 stats-text" id="statsText"></div>
<div class="col-4"> </div>
</div>
</div>
The way I've adressed the problem is based on using CSS Grid to create the initial size of the element in which you're showing your messages, and also adding the messages to the HTML, rather than replacing text.
While you could – of course – establish the sizes of the elements by positioning the content off-screen to inform the necessary sizing, and then animate to those dimensions before showing the message on-screen, that's more work than feels necessary.
My suggested approach is below, with explanatory comments in the code itself:
// using the '.stats' selector to obtain a jQuery Object containing
// all of the elements with that class-name in the document,
// we then use the attr() method to set the custom data-index attribute
// for later use:
$('.stats').attr('data-index', function(i) {
return i + 1;
// rather than the hover() method we use the on() method instead to handle
// both 'mouseenter' and 'mouseleave' events, and we pass the Event Object,
// as 'evt', into the anonymous function:
}).on('mouseenter mouseleave', function(evt) {
// here we use jQuery's data() method to retrieve the value of the
// data-index custom-attribute:
let index = $(this).data('index');
// here we retrieve the .message element which has the same
// data-index attribute and attribute-value, which is also within
// a .marketing element:
$(`.marketing .message[data-index="${index}"]`)
// we then use the toggleClass() method to add, or remove,
// the 'visible' class to the relevant .message element
// depending on whether the assessment returns true or false;
// if the evt.type is exactly-equal to 'mouseenter' the
// assessment returns Boolean true, and the class is added;
// otherwise Boolean false is returned and the class is
// removed:
.toggleClass('visible', evt.type === 'mouseenter');
});
$('input').on('input', function(){
$('main').css('--textSize',`${$(this).val()}rem`)
}).change();
/* a basic CSS reset to ensure that all elements
are sized in similar ways: */
*,
::before,
::after {
box-sizing: border-box;
font-size: 1rem;
font-weight: normal;
line-height: 1.5;
margin: 0;
padding: 0;
}
/* defining CSS Grid as the layout of
the <main> element: */
main {
display: grid;
/* defining three equal-width columns, each
of one fractional-unit of the available
space: */
grid-template-columns: repeat(3, 1fr);
margin: 0.5em auto;
width: 90vw;
}
/* I removed the inline <style> attribute from the
various elements, since it made the HTML noisier
than I'd like (adjust to taste of course): */
.stats > :is(h1, h2, h3) {
text-align: center;
}
/* I assumed that the messages should be full-width,
so here I defined the .marketing element should
start in the first track and end in the last: */
.marketing {
grid-column: 1 / -1;
}
/* again, using CSS Grid for the element that holds the
marketing messages: */
.marketing > div {
display: grid;
/* defining a single named area in which the marketing
claims should appear: */
grid-template-areas: "claims";
}
.marketing > div > .message {
/* here we position all of the .message elements into
the same grid area; which allows the largest grid-item
to define the size of that grid area: */
grid-area: claims;
/* effectively hiding the elements, and centring the text: */
opacity: 0;
pointer-events: none;
text-align: center;
user-select: none;
z-index: -1;
}
/* this is the 'background' element against which the .message
will be displayed, this can be easily adjusted or the
.message elements themselves can have their own background: */
.marketing > div > .mask {
background: linear-gradient(135deg, lime, #ffaf);
grid-area: claims;
}
/* when the 'visible' class-name is added to the .message elements
this CSS promotes their visibility, by raising their opacity to
1 (fully visible), raising their z-index above the background
and re-enabling pointer events and user-selection: */
.marketing > div > .message.visible {
opacity: 1;
pointer-events: auto;
user-select: auto;
z-index: 2;
}
.message:nth-child(2) {
font-size: var(--textSize, inherit);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!-- this is absolutely irrelevant to the demo, but does demonstrate how the
grid size automatically adjusts to the size of the largest element -->
<label>Adjust text-size of the second <code>message</code> element to:
<input type="number"
min="0.5"
max="20"
step="0.5"
value="1" /></label>
<!-- using the <main> element as a wrapping block for the posted content; -->
<main>
<!-- I removed the 'stats-text-n' class-name, since that would seem
to be more use as an id (given its role in uniquely identifying
a specific element, and also because that makes your code
inherently non-reusable; whereas each element has a 'stats' class-
name which allows us to generalise the JavaScript -->
<div class="col-3 stats">
<h1 class="stats-1">11</h1>
<h2 class="stats-2">Million</h2>
<h3 class="stats-3">Revenue Generated</h3>
</div>
<div class="col-3 stats">
<h1 class="stats-1">9</h1>
<h2 class="stats-2">Years</h2>
<h3 class="stats-3">In The Making</h3>
</div>
<div class="col-3 stats">
<h1 class="stats-1">6</h1>
<h2 class="stats-2">Times</h2>
<h3 class="stats-3">Return On Ad Spend</h3>
</div>
<!-- here I added the 'marketing' class-name, since the 'card-2-desktop' seems
as though it may be a product of a framework -->
<div class="card-2-desktop marketing">
<div class="row">
<!-- these messages were taken from your jQuery code, and placed inside of
the '.row' element, along with a custom data-* attribute which indicates
which of the '.stats' elements it refers to: -->
<div class="message" data-index="1">Our client’s monetary milestones are driven by our social tactics and digital marketing.</div>
<div class="message" data-index="2">Our experience is from more than just a couple of wins - it’s from learning through years of wins and losses.</div>
<div class="message" data-index="3">Our clients currently see a minimum average of 5.4 times return on ad spend.</div>
<!-- an element to act as the background of the other elements, this is
entirely optional and largely irrelevant -->
<div class="mask"></div>
</div>
</div>
</main>
JS Fiddle demo.
Of course, anything that can be accomplished in jQuery can also be achieved in native JavaScript; again, explanatory notes are in the comments of the code below:
// we use Array.from() to convert the NodeList returned by
// document.querySelectorAll() into an Array, in order to
// use Array methods later:
const messages = Array.from(
// here we retrieve all .message elements within a .marketing
// element:
document.querySelectorAll('.marketing .message')
),
// defining the toggle function, using Arrow syntax, and passing
// the Event Object ('evt') into the function:
toggle = (evt) => {
// we use 'currentTarget' property of the Event Object to find
// the element to which the event-handler was bound, as opposed
// to the 'target' property which simply returns the element
// upon which the event was initially fired; from that element
// we retrieve the data-index attribute-value:
let index = evt.currentTarget.dataset.index,
// here we filter the Array of .message elements to find the
// element(s) matching the the supplied filter, using an
// Arrow function to pass the current Array-element into
// the function body:
message = messages.filter(
// here we're looking to retain elements whose data-index
// attribute-value matches that of the .stats element
// upon which the event-handler was triggered:
(msg) => msg.dataset.index === index
);
// Array.prototype.filter() returns an Array, so here we use
// Array.prototype.forEach() to iterate through that Array:
message.forEach(
// here we toggle the 'visible' class-name on the retained
// .message elements, if the Event-type (evt.type) is exactly
// equal to 'mouseenter' the assessment returns Boolean true,
// and the class-name is added; otherwise Boolean false is
// returned and the class-name is removed (this generates no
// error if the class-name addition or removal would match
// the existing state):
(msg) => msg.classList.toggle('visible', evt.type === 'mouseenter')
);
};
// here we retrieve all elements matching the supplied CSS selector,
// and use NodeList.prototype.forEach() to iterate over that NoseList:
document.querySelectorAll('.stats').forEach(
// here we pass in a reference to the current Node of the NodeList
// (stat) and the index of that Node in the NodeList (i):
(stat, i) => {
// here we set the data-index attribute to be equal to the index
// plus 1 (to match the 1-based index in the HTML attributes I
// added):
stat.dataset.index = i + 1;
// and then bind the toggle() function - note the deliberate
// omission of the parentheses in the below code - as the
// event-handler for both the 'mouseenter' and 'mouseeout'
// events:
stat.addEventListener('mouseenter', toggle);
stat.addEventListener('mouseleave', toggle);
});
// again, largely irrelevant to the demo but demonstrates how the font-size
// determines the grid-area size to avoid size jumps between 'empty' and
// 'populated':
document.querySelector('input').addEventListener('input', (evt) =>
document.querySelectorAll('.marketing')
.forEach(
(el) => el.style.setProperty(
'--textSize',
`${evt.currentTarget.value}rem`)
)
);
*,
::before,
::after {
box-sizing: border-box;
font-size: 1rem;
font-weight: normal;
line-height: 1.5;
margin: 0;
padding: 0;
}
main {
display: grid;
grid-template-columns: repeat(3, 1fr);
margin: 0.5em auto;
width: 90vw;
}
.stats > :is(h1, h2, h3) {
text-align: center;
}
.marketing {
grid-column: 1 / -1;
}
.marketing > div {
display: grid;
grid-template-areas: "claims";
}
.marketing > div > .message {
grid-area: claims;
opacity: 0;
pointer-events: none;
text-align: center;
user-select: none;
z-index: -1;
}
.marketing > div > .mask {
background: linear-gradient(135deg, lime, #ffaf);
grid-area: claims;
}
.marketing > div > .message.visible {
opacity: 1;
pointer-events: auto;
user-select: auto;
z-index: 2;
}
.message:nth-child(2) {
font-size: var(--textSize, inherit);
}
<label>Adjust text-size of the second <code>message</code> element to:
<input type="number" min="0.5" max="20" step="0.5" value="1" /></label>
<main>
<div class="col-3 stats">
<h1 class="stats-1">11</h1>
<h2 class="stats-2">Million</h2>
<h3 class="stats-3">Revenue Generated</h3>
</div>
<div class="col-3 stats">
<h1 class="stats-1">9</h1>
<h2 class="stats-2">Years</h2>
<h3 class="stats-3">In The Making</h3>
</div>
<div class="col-3 stats">
<h1 class="stats-1">6</h1>
<h2 class="stats-2">Times</h2>
<h3 class="stats-3">Return On Ad Spend</h3>
</div>
<div class="card-2-desktop marketing">
<div class="row">
<div class="message" data-index="1">Our client’s monetary milestones are driven by our social tactics and digital marketing.</div>
<div class="message" data-index="2">Our experience is from more than just a couple of wins - it’s from learning through years of wins and losses.</div>
<div class="message" data-index="3">Our clients currently see a minimum average of 5.4 times return on ad spend.</div>
<div class="mask"></div>
</div>
</div>
</main>
JS Fiddle demo.
References:
CSS:
Attribute-selectors.
:is().
JavaScript:
Arrow functions.
Array.from().
Array.prototype.filter().
document.querySelectorAll().
Element.classList API.
EventTarget.addEventListener().
HTMLElement.dataset.
NodeList.prototype.forEach().
Template literals.
jQuery:
attr().
change().
data().
on().
toggleClass().
val().

Change div height back to dynamic

I have the code below to change the height of a div to equal that of its parent.
$('#infodiv').css("height",$("#infocol").outerHeight());
The problem is that the height of the child element #infocol, is no longer dynamic if i load new content inside of it. Is there a way to make the child element dynamic again after i have set the height with the above code?
I have tried to reconfigure its height after the content is loaded with the same code, but so far that hasn't worked.
There is a way you can solve this issue using ResizeObserver
However, note that it's not supported in some browsers, check the page I've linked for further details.
Here is a working example:
$(function () {
$("#add-content").click(function () {
$(".first-col").append("<p>More dynamic content...</p>");
});
// keep the second-col same size as first
$(".second-col").css('height', $(".first-col").outerHeight());
const resizeObserver = new ResizeObserver(function (entries) {
for (let entry of entries) {
// once one of the entry changes we want to update the other size too!
$(".second-col").css('height', $(entry.target).outerHeight());
}
});
// We need to pass the actual DOM node, hence the [0]
resizeObserver.observe($(".first-col")[0]);
});
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
.container {
width: 23.5rem;
margin: 1rem auto;
}
.first-col {
background: cornflowerblue;
}
.second-col {
background: crimson;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<div class="first-col">
<p>Some content</p>
<p>Some content</p>
<button id="add-content">Add content</button>
</div>
<div class="second-col"></div>
</div>
Though, I suggest before implementing it like that, that you look into how flex works or simply even min-height might be the proper tool for the issue here. If you're out of options, feel free to use ResizeObserver, but it's considered an exotic solution!

How to automatically scroll horizontally as page width increase

I am building a website that expands horizontally as user takes action like http://portal.azure.com style. When they click a button(from a list) in one div, the details of the selected items appear in another div beside it. this can get really long and over flow the mother div.
I am looking for a way i can automatically scroll the page to the right most edge when a new div overflows.
layout
<div style="overflow-x: auto">
<div layout="row">
<div class="col" style="width: 400px">
</div>
//SHOWN DYNAMICALLY
<div class="col" style="width: 400px">
</div>
//SHOWN DYNAMICALLY
<div class="col" style="width: 400px">
</div>
//SHOWN DYNAMICALLY
<div class="col" style="width: 400px">
</div>
//SHOWN DYNAMICALLY
<div class="col" style="width: 400px">
</div>
</div>
</div>
As you can see above, the first div shows by default but the other divs appear based on user interaction.
By the time the 3 div appears, it overflows.
How can i scroll to the right edge anytime it over flows? (you should really check out http://portal.azure.com to see what im talking about)
PS: i am using AngularJS. I am not using jquery. But i dont mind including it if its the only option
You can use plain Javascript for keeping the scroll to right.
Something like this:
var myDiv = document.getElementById("row");
myDiv.scrollLeft = myDiv.scrollWidth;
You need to fire the above function every time you add a new div. That way it will always automatically be scrolled when divs are dynamically added.
You will need to hook up the DOMNodeInserted event on your container. The function will be called whenever a div is added to your row container. This way you will not have to change anything in your existing code.
Here is a very simple example with dynamically added divs:
var num = 1,
btn = document.getElementById('btn'),
row = document.getElementById("row");
scroller(); // fire teh scroller right away for initial scroll
// function to keep it scrolled towards right
// function scroller() { row.scrollLeft = row.scrollWidth; }
// edited to add simple animation
function scroller() {
var maxScroll = row.scrollWidth - row.clientWidth; // required to stop
row.scrollLeft += 2;
if (row.scrollLeft < maxScroll) {
timer = window.setTimeout(scroller, 1000 / 60);
}
}
// hook up event to call scroller whenever an element is dynamically added
row.addEventListener("DOMNodeInserted", scroller);
// for demo to simluate dynamically adding divs
btn.addEventListener("click", function() {
var newDiv = document.createElement("div");
newDiv.setAttribute("class", "col");
num += 1; newDiv.innerText = num;
row.appendChild(newDiv);
});
div[layout] {
width: 500px; height: 140px; white-space: nowrap;
overflow: hidden; overflow-x: auto;
}
div.col { height: 140px; width: 400px; display: inline-block; text-align:center; }
div { border: 1px solid red; }
<div id="row" layout="row"><div class="col">1</div></div>
<button id="btn">Add</button>
Edit: Added simple animation using setTimeout (in order to keep jQuery away). Ideally you should be using requestAnimationFrame or a suitable library if you are already using one.

How to animate inserts and removes in a container with justify-content?

Using the flexbox justify-content property, elements can be distributed evenly in their container. However, I want to animate their positions when a new element is inserted or an existing one is removed.
I only managed to animate the height of the elements so far. However, there is a jump at the end of the animation since the gaps around the removed element that got animated to height: 0 vanish. Analogously, when inserting an element there is a jump at the beginning of the animation.
Is it possible to make an animation from end to end with justify-content? Here is an example to play with. Using CSS transition is preferred.
The main problem is that the behavior you are getting is the expected one.
In the very same instant that card.remove() is executed the flexbox justify-content property need to adjust the gaps around the removed element (as you said). And, as Paulie D has pointed out, there is nothing to animate about.
The only solution I can think about is to skip the flex thing and use javascript to create the necessary gaps among the card elements.
Here I leave the snippet:
var animation_time = 500;
var column_height = $('.column').height();
var cards_height = $('.card').height();
var cards_number;
var cards_total_height;
var space_to_be_distributed;
var placeholder_height;
function updateSizes(cards_number)
{
cards_total_height = cards_number * cards_height;
space_to_be_distributed = column_height - cards_total_height;
placeholder_height = space_to_be_distributed / (cards_number + 1);
}
updateSizes($('.card').length);
$('.placeholder').height(placeholder_height);
$(document).on('click', '.card', function () {
var card = $(this);
card.animate({height: 0, opacity: 0}, animation_time, function () {
card.remove();
});
updateSizes($('.card').length - 1);
var placeholder = card.next();
$('.placeholder').not(placeholder).animate({height: placeholder_height}, animation_time);
placeholder.animate({height: 0}, animation_time, function () {
placeholder.remove();
updateSizes($('.card').length);
$('.placeholder').animate({height: placeholder_height}, animation_time);
});
});
$('a').click(function () {
var card = $('<div class="card">');
card.css({opacity: 0, height: 0})
.appendTo('.column')
.animate({height: 25, opacity: 1}, animation_time);
var placeholder = $('<div class="placeholder">');
placeholder.css({height: 0})
.appendTo('.column');
updateSizes($('.card').length);
$('.placeholder').animate({height: placeholder_height}, animation_time);
});
body, html, .column {
height: 100%;
margin: 0;
}
.column {
float: left;
width: 100px;
background: navy;
overflow: hidden;
}
.card {
height: 25px;
width: 100px;
background: grey;
}
.placeholder {
height: 25px;
width: 100px;
}
<html>
<head>
<script src="http://code.jquery.com/jquery-2.1.3.min.js"></script>
</head>
<body>
<div class="column">
<div class="placeholder"></div>
<div class="card"></div>
<div class="placeholder"></div>
<div class="card"></div>
<div class="placeholder"></div>
<div class="card"></div>
<div class="placeholder"></div>
</div>
Add card
</body>
</html>
Hope it helps!
EDIT - I made the following changes in the code:
I change the fiddle for a SO snippet.
I forced an update of elements size at the end of the animation (in case you click to remove an element before the last one has been completely removed)
I change the size of the elementes to adapt it to the (small) SO snippet window.

How to lock height of two divs together?

I need to create two divs with same height. The height of each div is different on every page (height depends on content). Is there any way how to lock the height of two divs together? Here is a jsfiddle (I need to increse the height of div C based on div A and conversely).
Note: I cant use table or parent div. I am a newbie in JavaScript, so I hope that it can be done without it.
<div class="a">
<brdsds><br><br><br><bdsdsr><br><br><br>ds<br>dsds<br>dsd
</div>
<div class="b">
dsdds
</div>
<div class="c">
dsdds
</div>
You can use display:table-cell, first remove the float and add this:
div {
width 30px;
display:table-cell;/*Add this*/
/*float:left; Remove this*/
}
Check this Demo http://jsfiddle.net/8zPD2/1/
Before use this check the Compatibility
Just need to use this CSS:
.a,
.c {
max-height: 200px;
}
try this:
<div class="divmaster">
<div class="divchild">
<brdsds><br><br><br><bdsdsr><br><br><br>ds<br>dsds<br>dsd
</div>
<div class="divchild">
dsdds
</div>
<div class="divchild">
dsdds
</div>
and the css:
.divmaster{
display:table;
}
.divChild{
height: 100%;
}
If you want to try this in JavaScript , Use this code:
DEMO
$(function(){
setHeight = function (src, target) {
h = src.height();
target.css('height', h + 'px');
}
content = $('.a');
imagediv = $('.b');
setHeight(content, imagediv);
});
Just set your div to display: table-cell, and then remove the float: left.
CSS
div {
display: table-cell;
width 30px;
}
.a {
background-color: #e9d8b7;
}
.b {
background-color:blue;
}
Check this: http://jsfiddle.net/8zPD2/6/
Set min height to height of the div which has high height. Say if your div A has highest height the use that height to all divs. Its not possible with css if you dont know which div might have heigest div. As you asked how to do it only with css here it is
.a,.b,.c{ min-height:200px; max-height:400px; }

Categories