I have a flexbox container with scrolling along the x axis. It scrolls properly, but for some reason, many items within the container are hidden to the left of the screen, outside of the display. I have no idea why and am looking to make it such that the first element in the list is the first element seen in the leftmost box of the flexbox.
.home-carousel-cards {
display: flex;
flex-direction: row;
overflow-x: auto;
flex-shrink: 0;
margin: 0 -1px;
justify-content: center;
}
.home-item-card {
width: 241px;
min-width: 220px;
height: 300px;
background: white;
border-radius: 16px;
cursor: pointer;
margin: 0 1px;
border: 1px solid black;
}
The result:
The blue highlighted div is the first visible element. As you can see, the first shoe actually seen is certainly not the first element in the list, and all of the previous elements are not visible. I want the user to scroll right to the end of the list but can't get past this.
Related
I have a scrollable div area, I want to detect user to hover on items inside.
I want to group these items and put a handle on hover so I can drag them as a group.
But items needs to be flat in DOM in only .wrap div, even though they are logically grouped together.
What is the best way to detect a handle on mouse hover on these groups?
Finally I want to absolutely position these items when dropped in place.
Obviously I tried getBoundingClientRect, scrollTop, and other stuff to get a normalized mouse coordinate on the target wrapper element.
I think one way would be to strategically place handle divs within the wrapper element and natively detect onMouseOver event, what do you think?
body {
margin: 0;
padding: 0;
}
.ok {
background: #ccc;
position: relative;
width: 100vw;
height: 100vh;
display: flex;
}
.wrap {
background: white;
position: absolute;
top: 0;
left: 0;
height: 30%;
width: 100%;
display: flex;
flex-flow: column;
gap: 0.2em;
overflow-y: auto;
}
.wrap item {
flex-shrink: 0;
background: orange;
padding: 1em;
width: 100%;
height: 4em;
}
<div class='ok'>
<div class='wrap'>
<item> <span> text </span> <span> world </span> </item>
<item>asdf</item>
</div>
</div>
Here's what happens when unfixed and it's the behaviour I want but I want navbar to be fixed
Here's what happens when fixed: it doesn't move the content (it is behind this dropdown)
// scss for the nav
.filterbar {
position: fixed;
top: 0;
box-shadow: 0 0 15px black;
width: 100%;
// for info section
.filters-info {
margin-top: 110px;
display: flex;
justify-content: space-between;
}
How to fix this? (margin-bottom didn't help). I have two ideas: 1. to get toggleFilterbar prop and to change the styling based on this 2. to make the nav position absolute and then to change it to fixed. However, I guess there must be a simplier css way to fix this
Give position:relative; to .filters-info
and
Replace margin-top: 110px; to top: 110px;
i have a sticky nav that when it sticks (position: fixed being applied) the width is changing to push the right of the navbar off the screen.
a screen recording example
a codesandbox eample
Using react/hooks and styled components. a hook is applying the prop of sticky: true (see code below).
I have tried a few different combinations of setting width: 100% or width: 100vw in both the non-sticky and sticky styles.
in the video you can see 2 things happening when the nav becomes "sticky". the border-radius-bottom-right is disappearing and the content of the nav is being pushed to the right. When not sticky, the nav has a width of 808px, when sticky it grows to 840px. To be clear I'm not saying the border radius style is being removed, but the border right is now off screen.
the code for the nav:
const Wrapper = styled.div`
padding: 1rem;
display: flex;
justify-content: center;
font-size: 1.5rem;
background-color: white;
color: black;
/* width: auto; */
/* width: 100%; */
z-index: 1;
margin: 0;
box-shadow: 0px 2px 10px #273136;
height: 30px;
border-radius: 0 0 10px 10px;
${props => props.sticky && css`
position: fixed;
top: 0;
width: 100vw;
`}
`;
This is being rendered inside of another wrapper component, wrapping the entire app, with the following styles:
text-align: center;
font-size: 10px;
color: black;
display: flex;
flex-direction: column;
max-width: 100vw;
You set widht:100vw to the fixed element which makes wider than the body because vw doesn't care about the scrollbar it will be difficult to work with, i suggest you use width:100%
Also because you have box-sizing set to content-box the padding and border won't be considered as content so they will influence the width, and let's not forget about the default margin:8px on the body
to accommodate for all this we can use calc()
instead of 100vw you should use 100% because 100% gives us the exact width of the parent excluding the width of the scrollbar.
Solution
After you set position:fixed
You also add
left:8px; // to push it 8px from the left because of the default margins on the body
width:calc(100% - 48px);
Why 48x ?
left padding (16p) + right padding(16px) + left body margin(8px) + right body margin(8px) = 48px
Why left body margin ? didn't we use left:8px to deal with it ?
Yes we did and by pushing it we simply added it the other end.
I'm making an element in javascript and appending it to a flex container. The container I'm appending it to has a button in it and a display none div. I want the element I'm making to be positioned at the top of the div I'm appending it to, and I styled the class it has with align-self: flex-start, but for some reason this is doing nothing. Align-self: flex-end doesn't work either or any of the other align-self's. Here is my code-
// //handler to show text from eventData array
document.addEventListener('click', (e)=> {
let noEvents = document.getElementsByClassName('no-Events')[0];
let eventsDescContainer = document.querySelector('.events');
if(e.target.classList.contains('day')){
[...eventData['events']].forEach((event)=>{
if(event['day']===e.target.innerHTML && event['month']===headerMonths.innerHTML && event['year']===headerYears.innerHTML){
//span element to put Event text into
let eventDesc = `${event['description']}`
const span = document.createElement('span');
let EventText = document.createTextNode(eventDesc);;
//clear previous events message
noEvents.style.display='none';
clearEventText();
//append to container
span.appendChild(EventText)
span.classList.add('event-desc', 'event-message');
eventsDescContainer.appendChild(span);
} else {
clearEventText();
noEvents.style.display='initial';
noEvents.innerHTML = `There are no events on ${headerMonths.innerHTML} ${e.target.innerHTML} ${headerYears.innerHTML}`;
}
});
}
});
<div class='events'>
//this span is hidden
<span class='no-Events event-message'>There are no events today</span> //this button has no styles on it, it is just plain html
<button class='show-event-form rotate'>Add new event</button>
//This is the span I want to go at the top of the container but it is positioned after the button
<span class='event-desc event-message'>text</span>
</div>
Here is the html for the container and the span I created. The button has no styles.
.events{
height: 100%;
display:flex;
flex-direction: column;
align-items: center; /*center children vertically*/
overflow-y: auto;
}
.events .event-message {
align-items: center;
width: 80%;
text-align: center;
margin: 20px auto;
padding: 10px 0;
background-image: linear-gradient(to right, #649173, #dbd5a4 );
border-radius: 3px;
box-shadow: 3px 6px 10px #393a39;
}
//this is not working
.event-desc {
align-self: flex-start;
}
I changed the direction of the flex-direction in my container to flex-direction:column-reverse and justify-content:start to send it to the top of my container and this solved my problem. I'm still not sure why align-self was working though.
You have this in your code:
.events{
height: 100%;
display:flex;
flex-direction: column;
align-items: center; /*center children vertically*/
overflow-y: auto;
}
Your comment suggests a misconception: align-items: center does not center the children vertically in a column-direction container. It centers them horizontally.
The justify-* properties apply to the main axis.
The align-* properties apply to the cross axis.
These axes shift, depending on flex-direction.
Here's a complete explanation:
In CSS Flexbox, why are there no "justify-items" and "justify-self" properties?
I want all 100% height elements to expand when the size of the body expands.
In the example pressing the button will add a red div - the two columns adjacent should stretch to account for this. In the end all columns should reach the bottom completely, one with blue then red, the other two just blue.
I'm looking into flex, and it doesn't seem like this would work, but any suggestions are appreciated.
In any case best solution is CSS, but if this is impossible pure JS is also fine.
span = document.getElementsByTagName("span")[0];
function addelem() {
span.appendChild(document.createElement('div'));
};
html, body{
height: 100%;
}
span {
display: inline-block;
background-color: blue;
width: 30px;
height: 100%;
vertical-align: top;
}
div {
background-color: red;
width: 30px;
height: 30px;
}
<span><span></span></span>
<span></span>
<span><button onclick="return addelem()">+</button></span>
This is what I expect the frame to look like at the bottom after button is pressed and scrolled down:
EDIT
I changed the snippet so the button appends the div to an existing child and causes overflow, as per the comments below suggest.
An initial setting of a flex container is align-items: stretch. This means that flex items will expand to cover the full length of the container along the cross axis.
In a container with flex-direction: row, the cross axis is vertical, so items will expand to full height.
In your demo code, the divs (red) are being added as children of a span column (blue). These divs are being added to the end, forcing the column to grow.
In a row-direction flex container, with no heights specified that would override align-items: stretch, the other columns will follow suit.
span = document.getElementsByTagName("span")[0];
function addelem() {
span.appendChild(document.createElement('div'));
};
body {
display: flex;
min-height: 100vh;
}
body > span {
width: 30px;
margin-right: 5px;
background-color: blue;
display: flex;
flex-direction: column;
}
body > span:first-child span {
flex: 0 0 100vh;
}
div {
background-color: red;
width: 30px;
height: 30px;
}
button {
margin-bottom: auto;
}
<span><span></span></span>
<span></span>
<span><button onclick="return addelem()">+</button></span>
You should use Flexbox twice, once in the outer container, and once in the container containing the appended child elements.
Here is your modified code:
span = document.getElementsByTagName("span")[0];
function addelem() {
span.appendChild(document.createElement('div'));
};
html, body{
height: 100%;
/* new */
display: flex;
}
/* new */
body > span{margin-right: 4px;}
span {
/*display: inline-block;*/
background-color: blue;
width: 30px;
height: 100%;
vertical-align: top;
/* new */
display: flex;
flex-flow: column;
align-items: flex-end;
}
div {
background-color: red;
width: 30px;
height: 30px;
/* new */
flex: 1 0 auto;
}
<span><span></span></span>
<span></span>
<span><button onclick="return addelem()">+</button></span>