align-self:flex start is not sending child element to the top - javascript

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?

Related

Why is horizontal scroll on flexbox hiding elements to the left?

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.

Flexbox item (hide and show) modify the alignment of my previous items, what can i do?

I have a div with display:flex, and i have 4 items inside but the last item is a span which is displayed only after pressing a button and this span started with display:none.
The items are centered in the div vertically and horizontally.
When i press the button, the span appear but change the position of previous elements.
This is the image of first 3 elements centered in the right way with span display:none
This is the image of first 4 elements
As you can see, the first three elements, when appear the span, they are shifted up and to the left.
I want to keep static the position of the first 3 elements when span appear.
I want the first three elements centered like the first image, and span appear below the third element but without shift the other elements.
What can i do? Any suggestions?
Thank you in advance.
HTML:
<div id="buy">
<p>Prezzo: 39,10 €</p>
<div id="quantityDiv"></div>
<button id="button0">Aggiungi al carrello</button>
<span id="messageAdd0"></span>
</div>
CSS:
#buy {
margin-left: auto;
text-align: center;
display: flex;
flex-direction: column;
justify-content: center;
}
#buy > * {
margin: 0 auto;
}
#buy span {
background: #24252A;
display: none;
}
JS just use hide() and show() for the span when button is pressed.
Since you cannot use justify-self: end; on that specific element without not affecting the positions of the other flex child elements -
the best you can do so far (unless a better idea emerges) is to use position:absolute on that element with top:100% inside a position:relative parent:
.product {
display: flex;
}
.buy {
position: relative; /* Add this one */
margin-left: auto;
text-align: center;
display: flex;
flex-direction: column;
justify-content: center;
}
.buy > * {
margin: 0 auto;
}
.buy > .messageAdd {
position: absolute;
top: 100%;
right: 0;
white-space: nowrap;
color: red;
}
<div class="product">
<h1>Prodotto 1</h1>
<div class="buy">
<p>Prezzo: 39,10 €</p>
<div class="quantityDiv"></div>
<button class="button" disabled>Aggiungi al carrello</button>
<span class="messageAdd">È stato raggiunto il limite di 5 biglietti!</span>
</div>
</div>
Also, don't use IDs instead of classes. Use classes. ID should be unique!
Also, SEO-wise, don't use more than one h1-per-document.
Modify your HTML!
You could instead modify your HTML markup, by introducing a parent for the product specification:
.product {
display: flex;
}
.buy {
display: flex;
flex-direction: column;
margin-left: auto;
}
.buy-specs {
display: flex;
flex-direction: column;
align-items: center;
}
.buy > * {
margin-left: auto;
}
.buy-message {
color: red;
}
<div class="product">
<h1>Prodotto 1</h1>
<div class="buy">
<div class="buy-specs">
<p class="buy-specs-price">Prezzo: 39,10 €</p>
<div class="buy-specs-quantity"></div>
<button class="buy-specs-add button" disabled>Aggiungi al carrello</button>
</div>
<span class="buy-message">È stato raggiunto il limite di 5 biglietti!</span>
</div>
</div>
make another div for the span element that you want to hide and show after the click event and then set its position to absolute which will not allow the item to change the other elements position when appearing.
you could solve this by simply wrapping the span with div and then give suitable width and height for the div

How can I get this containing div to take the width of its child elements?

I would like fave_hold to remain at 100% of it's containing div, but I would like .faves to have a width only of its child elements. The child elements are dynamically rendered and have a defined width.
Here is the React/JSX.
<div id = 'fave_hold'>
{this.props.MenuFave.current === '1' &&
<div className = 'faves' id = 'fave_hold_arc' >
{tags1}
</div>
}
{this.props.MenuFave.current === '280' &&
<div className = 'faves' id = 'fave_hold_news' >
{tags280}
</div>
}
{this.props.MenuFave.current === '268' &&
<div className = 'faves' id = 'fave_hold_news' >
{tags268}
</div>
}
</div>
</div>
Here is the CSS
#fave_hold{
width: 100%;
height: 100%;
}
.faves{
height: 100%;
}
I have tried fiddling with the display to no avail.
Here is a screenshot.
The end goal is to center the content. And this is how I want to do it.
Here is the online prototype.
Your children are set as float so they are out of flow, the parent will ignore their size.
I would go for a different approach and remove the float and use flex.
.faves {
display: flex;
justify-content: space-around;
flex-wrap: wrap;
}
And remove the position:relative and 'float' from .bookmark_page.
So you left with something like this:
.bookmark_page {
border-radius: 4px;
width: 250px;
margin: 6px;
border: 6px solid white;
box-shadow: 0px 1px 3px rgba(34,25,25,0.4);
-webkit-box-shadow: 0px 1px 3px rgba(34,25,25,0.4);
}
With these changes you should get a result like this:
And on small screen:
Edit
how do I get rid of the mess at the bottom of each child element now?
I just noticed you meant the children's "mess" in the bottom.
You can set .faves this way to get what you want:
.faves {
display: flex;
align-items: flex-start;
flex-wrap: wrap;
}
i would consider setting the children's width (.bookmark_page) a bit higher, maybe 260px.
The result:
You can use display: inline-flex on your faves.

Increase the height of all elements when one element increases (equal height columns)

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>

Remove a class when two divs overlap

I have used flexbox to center my content vertically inside of 'main' tag, however when too much content is added it spills over into the 'header'. Is there a way I can calculate that if the div goes above a certain vertical position on screen (256px - height set as header), it removes a class from the 'main' (currently set to .vertical).
I know that the .removeClass() removes the class, but I dont know where to start with the vertical position calculation.
HTML
<header>Nav</header>
<main class="vertical">A lot of text here</main>
CSS
body, html{margin:0; height:100%}
header{width:100%; height:256px; background:red;}
main{width:100%; height: calc(100% - 256px); background:#fff;}
.vertical{
display: flex;
flex-direction: column;
justify-content: center;
}
Fiddle
I do hope that makes sense.
Many thanks Thanks.
I may misunderstand your goal, but it doesn't seem like you need to calculate the position on the screen. Since you have a Nav bar, it should always be visible and the content shouldn't overlap. I made a few changes to your code that allows the content to always sit underneath the header using justify-content: flex-start.
body, html {
margin: 0;
height: 100%
}
header {
display: block;
width: 100%;
height: 256px;
background: red;
}
main {
width: 100%;
height: 100%;
background: #fff;
}
.vertical{
display: flex;
flex-direction: column;
justify-content: flex-start;
}
If you still want to align the text differently, you could nest the content within another tag inside .vertical. Like so:
<header>Nav</header>
<main class="vertical">
<p class="content">all the text...</p>
</main>
And then add vertical styles to the .content section.

Categories

Resources