I'm trying to get all the letters displayed within container evenly spaced out using flexbox. Right now, if I enter sentence like "I like learning code", all elements are displayed within container and works ok, but if I use long word like "refrigerator", letters comes out of container. But I'm trying to keep all the letters to stay within container no matter how long the word is. I tried all the available flexbox techniques, but no luck. Tried max-width on container too. What am I missing? Here is the code in code sandbox: https://codesandbox.io/s/modern-sun-3u7b3?file=/src/App.js
import React from "react";
import "./styles.css";
function App() {
// let sentence = "I like learning code";
let sentence = "refrigerator";
const words = sentence.split(" ");
return (
<div className="pageContainer">
{words.map((word, i) => (
<div className="row" key={i}>
{[...word].map((letter) => (
<p className="letterBorder">{letter}</p>
))}
{i === words.length - 1 ? null : <p className="whiteSpaceBorder"></p>}
</div>
))}
</div>
);
}
export default App;
.letterBorder {
border: 25px;
background: grey;
padding: 20px;
width: 50px;
height: 30px;
flex-grow: 1;
margin-right: 4px;
margin-left: 4px;
}
.row {
display: flex;
justify-content: space-evenly;
min-width: 100%;
align-content: flex-start;
}
.whiteSpaceBorder {
border: 25px;
background: orange;
padding: 20px;
width: 50px;
height: 30px;
flex-grow: 1;
margin-right: 4px;
margin-left: 4px;
}
.pageContainer {
border-radius: 1rem;
text-align: center;
background: lightcyan;
height: 40rem;
width: 30rem;
margin: auto;
}
Your error is due to the hardcoded horizontal padding of your letterBorder class.
Replace
padding: 20px;
with
padding: 20px 0;
https://codesandbox.io/s/gracious-violet-qg1xt?file=/src/App.js
This is where the css property flex-wrap comes in handy. Flexbox items all try to fit into one line by default. However, you can make them wrap using flex-wrap: wrap.
Add it to your row class:
.row {
display: flex;
flex-wrap: wrap; /* Allow items in row to "wrap" to next line if needed */
justify-content: space-evenly;
min-width: 100%;
align-content: flex-start;
}
See this css-tricks page for a better visual explanation.
Related
I am building a website to be used on a mobile phone. The css is very straight forward however I can't seem to get the text to align in the same place vertically. Some browsers the text will appear completely at the bottom of the screen, other browsers show the text slightly above my footer (3rem), others show the browser maybe 6 rem from the bottom.
Mobile.js
const Mobile = () => {
return (
<div className={style.app}>
<div className={style.mainContent}>
<div className={style.address}>128 W 2nd St, Winona, MN 55987</div>
</div>
</div>
);
};
css
html,
body {
margin: 0;
/* height: 100% */
}
.app {
height: calc(100vh - 8rem);
width: 100vw;
background-size: cover;
display: flex;
justify-content: center;
margin-top: 5rem;
margin-bottom: 3rem;
position: relative;
}
.mainContent {
color: white;
width: 100%;
/* display: flex;
align-self: flex-end; */
margin-bottom: 1.5rem;
margin-left: 1rem;
position: absolute;
bottom: 3rem;
left: 0;
}
Now I have tried a bunch of different things such as using flex-end on .mainContent, and using a larger margin-bottom. I am really not sure whats going on here because the css looks very simple to me.
I would like my button, which contains 3 components (1 being on the far left, 2 being in the center, and 3 being on the far right (because of align-center: space between), which I need for another variant), to function like this, when the screen size is greater than 560px:
where flex-direction: row keeps it functioning how I want. Then, I want to change it slightly when the screen width drops below 560px. I would like to move the 1 component above the 2 and 3 components and be centered between them (horizontally), as can be seen here...
I was able to achieve the solution with the picture when I placed a div surrounding component 1 and 2, but then I cannot achieve the final solution when the screen width is below 560px. I have been able to achieve that solution as well when I pair component 2 and 3 within the same div as well, but that makes the wider function not work how I want either.
I imagine there's a way to achieve what I want without enforcing these div groupings, but I'm not really sure. I'm also somewhat new to Javascript, so any advice about something I've said would be appreciated too.
I used a breakpoint to change the ruleset for both the container element (button in your case) and the children.
The below example is in LESS, but you can see the compiled CSS in this codepen by using the dropdown on the CSS panel.
#mediumQuery: ~"screen and (max-width:560px)";
.container {
display : flex;
flex-direction: row;
column-gap : 20px;
border : 2px solid #yellow;
padding : 10px;
width : 100vw;
div {
display : inline-block;
border : 2px solid #purple;
width : 200px;
height : 100px;
font-size : 40px;
line-height : 100px;
text-align : center;
&:last-child{
margin-left: auto;
}
}
#media #mediumQuery {
display : block;
flex-direction : unset;
column-gap : unset;
border : 2px solid #lightBlue;
text-align : center;
div {
margin : 20px;
&:first-child {
display : block;
margin : auto;
}
}
}
}
you can put the div you want to be on top into another container and then play with #media queries and adjust how you want
main {
display: flex;
flex-wrap: wrap;
max-width: 560px;
border: 1px solid;
}
div {
width: 100px;
height: 100px;
border: 1px solid;
}
div:nth-child(3) {
margin-left: auto;
}
#media screen and (max-width: 560px) {
main {
justify-content: space-between;
}
section {
width: 100%;
}
section div {
margin: auto;
}
}
#media screen and (max-width: 240px) {
main {
flex-direction: column;
justify-content: center;
align-items: center;
}
div:nth-child(3) {
margin: auto;
}
}
<main>
<section>
<div>1</div>
</section>
<div>2</div>
<div>3</div>
</main>
.wrapper {
border: 5px solid pink;
display: flex;
flex-wrap: wrap;
justify-content: center;
}
.a-fc {
background-color: purple;
width: 300px;
/*height: 100px;*/
}
.b-fc {
background-color: orange;
display: flex;
flex-direction: column;
/*flex-wrap: wrap;*/
flex-basis:70px;
flex-grow:1;
}
.b-fc > * {
flex-grow: 1;
flex-basis: 100px;
}
.b-fc > *:nth-child(1) {
background-color: red;
}
.b-fc > *:nth-child(2) {
background-color: blue;
}
.b-fc > *:nth-child(3) {
background-color: green;
}
<div class="wrapper">
<div class="a-fc">
<div>a1</div>
</div>
<div class="b-fc">
<div>b1</div><div>b2</div><div>b3</div>
</div>
</div>
FC = flex-container.
FI = flex-item.
I am able to place .b-fc onto a new row when the space left for it to exist on the original row goes below 70px.
My task: I want b-fc's FIs to stack vertically when no new row is created/they don't wrap. I want b-fc's FIs to align horizontally when b-fc wraps.
Current solution
In the code-snippet above, I've tried to achieve my task by writing one set of properties that work for both scenarios by setting a `flex-basis` on `.b-fc`'s FIs. If the space left for `.b-fc`'s FIs is less than this flex-basis (100px), the FIs will stack vertically. The weakness: i) if `.b-fc`'s `width`'s larger than 300px, its FIs align horizontally ii) When `.b-fc` wraps, its FIs wrap when `.bf-c` is less than 300px.
Therefore, I'm figuring it'd be more powerful to be able to apply CSS when .b-fc wraps. Is this possible?
*Idea 1: CSS variables & JS*
Perhaps using CSS variables/SASS I could continually assess whether FC - .a-fc <= than 70px. If true, apply stylings to .b-fc.
Idea 2: media-queries
Another option is to test when row2 is made, use media queries to capture this and apply CSS to .b-fc with media queries.
P.S. Similar question has been asked here before in 2015. Maybe new techniques have transpired since.
For this particular case you can consider the use of max() combined with flex-basis. The trick is to either have 0px (horizontal item) or a very big value (vertical items).
You will note that this is not a generic solution and the value is based on your html structure:
395px = 300px (width of a-fx) + 70px (flex-basis of b-fc) + 10px (border of wrapper) + 16px (default body margin) - 1px
.wrapper {
border: 5px solid pink;
display: flex;
flex-wrap: wrap;
justify-content: center;
}
.a-fc {
background-color: purple;
width: 300px;
}
.b-fc {
background-color: orange;
display: flex;
flex-wrap: wrap;
flex-basis: 70px;
flex-grow: 1;
}
.b-fc>* {
flex-grow: 1;
flex-basis: max(0px, (100vw - 395px)*100);
height: 100px;
}
.b-fc>*:nth-child(1) {
background-color: red;
}
.b-fc>*:nth-child(2) {
background-color: blue;
}
.b-fc>*:nth-child(3) {
background-color: green;
}
<div class="wrapper">
<div class="a-fc">
<div>a1</div>
</div>
<div class="b-fc">
<div>b1</div>
<div>b2</div>
<div>b3</div>
</div>
</div>
So to answer your question: No, we cannot apply CSS on wrapping (CSS cannot detect wrapping) but we can always find workaround of each case.
Similar questions:
Without media queries how to achieve 3 column desktop to 1 column mobile layout
CSS grid maximum number of columns without media queries
I'm trying to get a React component I've built to display on the same line as the rest of the text, but it keeps appearing on a different line than the rest of the elements.
Here's my React code:
<div className={styles['top']}>
<span>WHAT PEOPLE ARE SAYING</span>
<div className={`pull-right ${styles['right']}`}>
<span className={`${styles['rating-words']}`}>{ratingWords}</span>
<Rating className={`${styles['overall-stars']}`}
percentage={this.state.overallPercentage}
color={"#00c18a"}
under={"white"}
/>
</div>
</div>
and the .scss:
.top {
margin: 30px 0;
font-weight: bold;
.right {
display: inline-block;
flex-direction: row;
}
.rating-words {
text-transform: uppercase;
}
}
and finally, a picture of what it looks like:
Both "VERY GOOD" and the rating stars should be on the same line. Any idea how to fix this?
If you have two child elements inside of .top this should work.
fiddle
.top {
margin: 30px 0;
font-weight: bold;
display: flex;
flex-direction: row;
justify-content: space-between;
.rating-words {
text-transform: uppercase;
}
.right {
}
}
I ended up getting it to work with the following based on what #Chad said though what #torkjels said ended up working better in another place.
.top {
margin-top: 40px;
margin-bottom: 30px;
font-weight: bold;
.right {
display: inline-flex;
flex-direction: row;
}
.rating-words {
text-transform: uppercase;
margin-right: 10px;
}
.overall-stars {
margin-top: -2px;
}
}
If you post a working jsfiddle or codepen it would be easier to help.
Try giving your overall-stars class display: inline-block. I assume it's already a block element, which makes it appear on a new line.
const top = {
// Other styles
display: 'flex',
flexDirection: 'row',
}
Might help.
I have a container with a bunch of equally sized elements. The container has a width of 100% up to a certain px amount, so if a user shrinks their screen down, elements from the first row may be moved down to the second row to fit, and from the second row to the third row, etc.
I'd like the .spacer div to act as a pseudo margin so that the first element in the second row of divs, no matter what div it actually is, will be spaced 250px out from the left side of the container. I want that .spacer div to always remain at a fixed point relative to the container (right at the beginning of the second row) but also affect the position of the first div in that row. How can I accomplish this with CSS? Open to JS solutions as well.
Here's a Codepen that shows the situation I'm describing:
https://codepen.io/anon/pen/QMMyLj
Any ideas?
Not sure, but check if you are looking something like this:
.container {
background-color: black;
width: 80%;
max-width: 1800px;
min-height: 1000px;
padding: 10px 5px;
text-align: center;
margin: 0 auto;
}
.square {
display: inline-block;
height: 250px;
width: 250px;
background-color: white;
float: none;
margin-left: 5px;
margin-right: 5px;
margin-bottom: 20px;
text-align: center;
line-height: 250px
}
<div class="container">
<div class="square">1</div>
<div class="square">2</div>
<div class="square">3</div>
<div class="square">4</div>
<div class="square">5</div>
<div class="square">6</div>
<div class="square">7</div>
<div class="square">8</div>
<div class="square">9</div>
<div class="square">10</div>
<div class="square">11</div>
<div class="square">12</div>
<div class="square">13</div>
<div class="square">14</div>
<div class="square">15</div>
</div>
Here is a possible solution using css grid and variables. It uses css-grid to layout the red spacer, and javascript to update the number of columns required. (Note that they are only supported in modern browsers http://caniuse.com/css-grid/embed)
CSS
:root {
--colNum: 1;
}
.container {
display: grid;
justify-content: left;
grid-template-columns: repeat(var(--colNum), auto);
}
.square {
height: 250px;
width: 250px;
background-color: white;
}
.spacer {
background-color: red;
width: 250px;
grid-row: 2 / span 1;
grid-col: 1 / span 1;
}
JS
function setNoOfColumns(){
columns = Math.floor(window.innerWidth / 250);
document.documentElement.style.setProperty("--colNum", columns);
}
window.addEventListener("resize", function(){
setNoOfColumns();
});
setNoOfColumns();
Code: https://codepen.io/anon/pen/mMMPwO