I have a container that can be scrolled through horizontally. This was done by rotating the container by 90 degrees.
This is however only a visual workaround: the visual horizontal scrolling is done by physical vertical scrolling. On mobile devices this is very counter-intuitive.
Is there any way to manipulate the scrolling behaviour so that the container can be scrolled through with horizontal touch gestures?
Here is a simplified demonstration of the container:
.item {
background: black;
height: 50px;
width: 50px;
margin: 5px;
}
.container {
background: yellow;
width: fit-content;
height: 300px;
overflow-y: scroll;
transform: rotate(-90deg);
transform-origin: top right;
}
<div class="container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
Instead of using transform, actualy place the elements side by side in a flex container.
Because you don't want the elements to shrink with the container size you a can set a min-width on the items:
.item {
background: black;
height: 50px;
width: 50px;
margin: 5px;
min-width:50px;
}
.container {
display:flex;
background: yellow;
width: 300px;
overflow-x: scroll;
}
<div class="container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
Related
This question already has answers here:
Can't scroll to top of flex item that is overflowing container
(12 answers)
Closed 1 year ago.
I have a column flexbox with width:100% and overflow-x:auto , inside this flexbox there are variable numbers of rows and each row can contain 1,2,4,8,16,... elements.
consider bellow example:
first row ---> has 1 element
second row ---> has 2 elements
third row ---> has 4 elements
forth row ---> has 8 elements
...
and elements on each row should be centered.
in my code all the left side elements will be cut off , how can I prevent this ??
const itemWidth = 300; //300px
document.querySelectorAll('.item').forEach((item) => {
item.style.width = `${itemWidth}px`;
});
document.querySelectorAll('.row').forEach((row, i) => {
row.style.width = `${
(Math.pow(2, i) + (Math.pow(2, i) - 1)) * itemWidth
}px`; //calc needed width of each row
});
.rows {
width: 100%;
overflow-x: auto;
display: flex;
flex-direction: column;
align-items: center;
}
.row {
display: flex;
justify-content: space-between;
margin-top: 20px;
}
.item {
height: 100px;
background-color: royalblue;
margin: 20px;
}
<div class="rows">
<div class="row">
<div class="item"></div>
</div>
<div class="row">
<div class="item"></div>
<div class="item"></div>
</div>
<div class="row">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
<div class="row">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
</div>
For the first div. You are assigning a width of only one item. So, flex items got cut off to left. Please check the below code. Get the length of items contains a max length of a row. Assign it to all the divs. If your unable to view the below code in snippet. Check it here - https://codepen.io/kcsmastermind/pen/MWpPBrY
const itemWidth = 300; //300px
document.querySelectorAll('.item').forEach((item) => {
item.style.width = `${itemWidth}px`;
});
let rows = document.getElementsByClassName("row");
let maxNumber = 0;
for (let i=0; i < rows.length; i++) {
if (maxNumber < rows[i].childElementCount) maxNumber = rows[i].childElementCount;
};
document.querySelectorAll('.row').forEach((row, i) => {
row.style.minWidth = `${
maxNumber * itemWidth
}px`; //calc needed width of each row
});
.rows {
display: flex;
flex-direction: column;
align-content: center;
width: 100%;
overflow-x: auto;
}
.row {
display: flex;
justify-content: center;
margin-top: 20px;
}
.item {
height: 100px;
background-color: royalblue;
margin: 20px;
}
<div class="rows">
<div class="row">
<div class="item"></div>
</div>
<div class="row">
<div class="item"></div>
<div class="item"></div>
</div>
<div class="row">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
<div class="row">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
</div>
Here's a pure CSS solution (I took some liberties with styling to hopefully make it easier to see what's going on):
https://jsfiddle.net/5hq924uf/1/
Rather than calculating element widths via Javascript, the .rows container width is set based on its child content with this rule:
width: min-content;
This then props the page open, preventing elements from getting cut off when centered using flex.
Note that while the min-content feature seems to be well-supported in modern browsers, it's not going to work in some legacy browsers, so be aware:
https://caniuse.com/mdn-css_properties_width_min-content
I'm creating a selector plugin (which can set active class to the multiple elements).
Algorithm:
onMouseDown create element;
onMouseMove while onMouseDown move to elements I want to select, my created element changes size.
onMouseUp get event target and do magic.
This is the short version due to shortness but I have a problem with getting proper event target. When I move to the right and bottom/top (my x axis gets positive), I'm getting the proper event target. But when my x-axis is negative I always getting e.target the element which changes size itself, not the elements I need.
const container = document.querySelector('.container');
let selector = null;
container.addEventListener('mousedown', (e) => {
selector = document.createElement('div');
selector.style.position = 'fixed';
selector.style.border = '1px dashed blue';
selector.style.width = '1px';
selector.style.height = '1px';
selector.style.left = e.clientX+'px'
selector.style.top = e.clientY+'px'
selector.className = "selector";
container.appendChild(selector);
const mouseDownClientX = e.clientX;
const mouseDownClientY = e.clientY;
document.onmousemove = e => {
renderselector(e, mouseDownClientX, mouseDownClientY);
}
document.onmouseup = e => {
console.log(e.target);
selector.remove();
}
});
function renderselector(e, mouseDownClientX, mouseDownClientY) {
const top = Math.min(e.clientY, mouseDownClientY);
const left = Math.min(e.clientX, mouseDownClientX)
const width = Math.abs(e.clientX - mouseDownClientX);
const height = Math.abs(e.clientY - mouseDownClientY);
selector.style.width = width + 'px';
selector.style.height = height + 'px';
selector.style.top = top+'px';
selector.style.left = left+'px';
}
* {
padding: 0px;
margin: 0px;
box-sizing: border-box;
}
.container {
display: flex;
justify-content: center;
align-content: center;
flex-wrap: wrap;
width: 50vw;
height: 100vh;
margin: 0 auto;
border: 1px solid gray;
}
.item {
padding: 20px;
flex: 0 0 50px;
border: 1px solid gray;
}
<div class='container'>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
Needed to change z-index of my selector to lesser than my divs.
How can I create a grid system like Flickr's explore page? https://www.flickr.com/explore
I've looked into Isotope (isotope.pkgd.js) but I can't seem to be able to arrange the grid based on the size of the images.
So far this is what I came up with:
HTML:
<h1>Isotope - masonry layout mode</h1>
<div class="isotope">
<div class="item width2 "></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item width2 "></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item width2 "></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item width2 "></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item width2 "></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item width2 "></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item width2 "></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item width2 "></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
CSS:
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
body {
font-family: sans-serif;
}
/* ---- isotope ---- */
.isotope {
background: #DDD;
max-width: 1200px;
}
/* clear fix */
.isotope:after {
content: '';
display: block;
clear: both;
}
/* ---- .item ---- */
.item {
float: left;
width: 100px;
height: 100px;
background: #0D8;
border: 2px solid #333;
border-color: hsla(0, 0%, 0%, 0.7);
}
.item.width2 { width: 200px; }
.item.height2 { height: 200px; }
JavaScript:
// external js:
// http://isotope.metafizzy.co/isotope.pkgd.js
$( function() {
$('.isotope').isotope({
itemSelector: '.item',
masonry: {
columnWidth: 100
}
});
});
Im not 100% sure on what you mean with order by image size. But to get the effect of flickr i would try something like this:
layoutMode: 'packery'
$('.isotope').isotope({
itemSelector: '.item',
layoutMode: 'packery',
masonry: {
columnWidth: 100
}
});
I think I'm probably doing something wrong that's incredibly obvious...
This is my HTML
<div id="container">
<div class="item"></div>
<div class="item w2"></div>
<div class="item"></div>
<div class="item w2"></div>
<div class="item h2"></div>
<div class="item"></div>
<div class="item h2"></div>
<div class="item w2 h2"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item h2"></div>
<div class="item"></div>
</div>
I'm calling jQuery 1.7.1 and modernizr in the head, and calling masonry.js and the below script before the /body
$(document).ready(function() {
$('#container').masonry({
columnWidth: 440,
itemSelector: '.item',
isFitWidth: false,
transitionDuration: 0,
});
});
Incidentally my CSS is below if that makes any difference
#container {padding: 5px;}
.item {
width: 220px;
height: 160px;
float: left;
margin: 5px;
background: #CCC;
}
.item.w2 {width: 440px;}
.item.h2 { height: 280px;}
No console errors but doesn't seem to be stacking how I would imagine
** see here - http://www.rsg-media.com/masonry/test.html
I would think it would appear a bit more like this
http://www.code-pal.com/wp-content/uploads/2013/01/masonry-css3-jquery-fallback.jpg
...or am I being an idiot?
done a snippet here, changed the width of w2 to a percentage and it moved them around a bit better... I've reset it to original now but I think there's your problem
$(document).ready(function() {
$('#container').masonry({
columnWidth: 440,
itemSelector: '.item',
isFitWidth: false,
transitionDuration: 0,
});
});
#container {padding: 5px;}
.item {
width: 220px;
height: 160px;
float: left;
margin: 5px;
background: #CCC;
}
.item.w2 {width: 440px;}
.item.h2 { height: 280px;}
<script src="http://desandro.github.io/masonry/jquery.masonry.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
<div class="item"></div>
<div class="item w2"></div>
<div class="item"></div>
<div class="item w2"></div>
<div class="item h2"></div>
<div class="item"></div>
<div class="item h2"></div>
<div class="item w2 h2"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item h2"></div>
<div class="item"></div>
</div>
I am practicing CSS with Masonry. I'm doing a bit of basic testing and seeing how everything gets displayed. However I am not sure how to fix this problem. I want to fit all of my pictures inside the .masonry class in my CSS but there is this little bit of space that occurs and I'm not sure how to fix it. I want all the boxes to be flush and no white space to be displayed between each box.
Here is the codepen:
http://codepen.io/anon/pen/Cpedg
my CSS:
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
body { font-family: sans-serif; }
.masonry{
margin: 0 auto;
background: #EEE;
max-width: 80%;
}
.masonry .item,
.masonry .grid-sizer {
width: 20%; /*item default width of 20%*/
margin: 0px;
}
.masonry .item,
.masonry .grid-sizer {
height: 60px; /* default hieght of image*/
float: left;
background: #D26;
border: 1px solid #343;
border-color: hsla(0, 0%, 0%, 0.5);
border-radius: 5px;
}
.item.w2 { width: 40%; } /* changes each item to these chracteristics*/
.item.h2 { height: 100px; }
.item.h3 { height: 130px; }
.item.h4 { height: 180px; }
my HTML:
<h1>Masonry - columnWidth</h1>
<div class="masonry js-masonry" data-masonry-options='{ "columnWidth": ".grid-sizer", "itemSelector": ".item" }'>
<div class="grid-sizer"></div>
<div class="item"></div>
<div class="item w2 h2"></div>
<div class="item h3"></div>
<div class="item h2"></div>
<div class="item w3"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item h2"></div>
<div class="item w2 h3"></div>
<div class="item"></div>
<div class="item h2"></div>
<div class="item"></div>
<div class="item w2 h2"></div>
<div class="item w2"></div>
<div class="item"></div>
<div class="item h2"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item h3"></div>
<div class="item h2"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item h2"></div>
</div>
You can remove those spaces between the cells by adding (or rather removing) margin and padding to (from) your body, like so:
body {
font-family: sans-serif;
margin: 0;
padding: 0;
}
That's a possible solution for the upper left arrow, but I'm not quite sure what the problem with the second arrow is?
So it turns out google chrome's zoom acts a bit funky sometimes. quick fix to realign everything is to press ctrl + 0 to realign everything!