Center responsive elements in horizontal scroll container - html

I have created a container (red border with line denoting the center) that scrolls horizontally if there is overflow.
The first child (purple block) of this container is always a button.
When you click this button, it adds additional children to the container.
What I am trying to do is figure out a way with pure CSS, so that the first child is always centered when the app is loaded, and the last child element in the container, if there is more than one child, can also be scrolled to the very center of the container.
I am having difficulties figuring this out because I have applied a min-width (i.e. 100px) in addition to a responsive width (i.e. 25vw) to the child elements.
The way I was initially planning on achieving this was by applying a padding-left to the parent container, and then an ::after pseudo element to :not(.first-child).children:last-child, but then I realized the approach is not sufficient if I want it to be completely responsive. However, I know I can manually calculate at which width min-width will be triggered and then use a #media query, but I am hoping there is a better way.
#container {
width: 100%;
height: 100%;
padding-left: ; /* Half the window width minus half the width of the child. */
overflow-x: scroll;
display: flex;
align-items: center;
background: skyblue;
box-sizing: border-box;
border: solid red 2px;
}
#container::-webkit-scrollbar {
display: none;
}
.children {
width: 25vw;
min-width: 100px;
height: 50%;
min-height: 200px;
position: relative;
margin-right: 5%;
display: flex;
justify-content: center;
align-items: center;
background: purple;
}
:not(.first-child).children:last-child::after {
content: '';
width: ; /* Half the window width minus half the width of the child. */
height: 100%;
position: relative; /* relative or absolute */
left: ; /* and offset appropriately. */
transform: ; /* */
}
Does anybody have any ideas of how to do this?

You can apply margin-left to the first child and to deal with the min-width you can use media query. When the screen is less than 400px the 25vw will be less than 100px and you change the value to consider the 100px.
#container {
position: fixed;
top:0;
left:0;
width: 100%;
height: 100%;
overflow-x: scroll;
display: flex;
align-items: center;
background:
linear-gradient(red,red) center/1px 100% no-repeat,
skyblue;
box-sizing: border-box;
border: solid red 2px;
}
#container::-webkit-scrollbar {
display: none;
}
.children {
width: 25vw;
min-width: 100px;
height: 40%;
min-height: 100px;
position: relative;
margin-right: 5px;
display: flex;
justify-content: center;
align-items: center;
background: purple;
flex-shrink:0; /* don't forget this to avoid the shrink */
}
.children:first-child {
margin-left: calc(50% - 12.5vw);
}
#media (max-width:400px) {
.children:first-child {
width: 25vw;
min-width: 100px;
margin-left: calc(50% - 50px);
}
}
<div id="container">
<div class="children"></div>
<div class="children"></div>
<div class="children"></div>
<div class="children"></div>
</div>
Without media query you can consider a pseudo element where you will have a max-width constraint:
#container {
position: fixed;
top:0;
left:0;
width: 100%;
height: 100%;
overflow-x: scroll;
display: flex;
align-items: center;
background:
linear-gradient(red,red) center/1px 100% no-repeat,
skyblue;
box-sizing: border-box;
border: solid red 2px;
}
#container::-webkit-scrollbar {
display: none;
}
.children {
width: 25vw;
min-width: 100px;
height: 40%;
min-height: 100px;
position: relative;
margin-right: 5px;
display: flex;
justify-content: center;
align-items: center;
background: purple;
flex-shrink:0;
}
#container:before {
content:"";
width: calc(50% - 12.5vw);
max-width:calc(50% - 50px);
flex-shrink:0;
}
<div id="container">
<div class="children"></div>
<div class="children"></div>
<div class="children"></div>
<div class="children"></div>
</div>

I was able to create a strictly responsive solution using calc, even though I am using vh as the width of the children. CSS is a savior.
#container {
--offset: calc(50vw - ((100vh / 100) * 20);
padding-left: var(--offset);
background: skyblue;
}
.children {
min-width: 40vh; /* vh is used for width to account for the height of window. */
min-height: 60vh;
position: relative;
background: purple;
}
:not(.first-child).children:last-child::after {
content: '';
width: var(--offset);
height: 1px;
position: absolute;
left: 100%;
}

Related

Scaling large div to fit flex container causes incorrect positioning

The goal is to scale content to fit within a container.
When the content is smaller than the container, the transformation works and the content is centered.
However, if the content is too big, positioning breaks. The content no longer honors the CSS rules to remain centered.
The scale value 0.300648 is meant to fit the large content (3036x2162) within the parent (900x650).
Even a smaller scale value like 0.2 fails to center the content properly.
How to get the content to remain centered, regardless of the scale value?
To clarify, both the scale factor and absolute position of the content are required.
This JSFiddle shows the problem, with the red div representing the content (and not being centered): https://jsfiddle.net/panabee/bwpa3snk/10/
#previewBox {
display: flex;
align-items: center;
justify-content: center;
width: 900px;
height: 650px;
border: 1px solid #E0E0E0;
border-radius: 5px;
}
.canvas-container {
width: 3036px;
height: 2162px;
position: relative;
user-select: none;
transform: scale(0.300648);
}
.content {
position: absolute;
background: red;
width: 3036px;
height: 2162px;
left: 0px;
top: 0px;
}
Here the content's scale will honor the size of its parent. I.e setting the scale to scale(1) would take up the parents entire container. Setting scale(.5) would take up half of the container, and remain the content-div centered. Please let me know if I didn't understand your question.
body {
display: flex;
height: 100vh;
align-items: center;
justify-content: center;
}
.canvas-container {
display: flex;
justify-content: center;
align-items: center;
width: 1000px;
height: 500px;
background-color: yellow;
}
.content {
display: flex;
width: 100%;
height: 100%;
background-color: black;
transform: scale(0.5);
}
<body>
<div class="canvas-container">
<div class="content"></div>
</div>
</body>
A couple of variations, one with overflow hidden and scale(2), the other without scale. Added max-width and max height 100 % to the content and set width and height to 100 % for the container. Larger px inside smaller px usually creates trouble in my experience, so the max sizes counter that.
#previewBox {
display: flex;
align-items: center;
justify-content: center;
width: 900px;
height: 650px;
border: 1px solid #E0E0E0;
border-radius: 5px;
overflow: hidden;
/* this prevents overflow since the scale is set to 2, it can also be set to auto to make it scrollable or removed entirely to get full overflow */
}
.canvas-container {
position: relative;
width: 100%;
height: 100%;
user-select: none;
transform: scale(2);
}
.content {
background: red;
width: 3036px;
height: 2162px;
max-width: 100%;
max-height: 100%;
}
<div id="previewBox">
<div class="canvas-container">
<div class="content"></div>
</div>
</div>
#previewBox {
display: flex;
align-items: center;
justify-content: center;
width: 900px;
height: 650px;
border: 1px solid #E0E0E0;
border-radius: 5px;
}
.canvas-container {
position: relative;
width: 100%;
height: 100%;
user-select: none;
/* removed scale since the size matches the container anyway */
}
.content {
background: red;
width: 3036px;
height: 2162px;
max-width: 100%;
max-height: 100%;
}
<div id="previewBox">
<div class="canvas-container">
<div class="content"></div>
</div>
</div>

Stack image over full page background in the middle

.wrapper{
display: inline-block;
position:relative;
}
.big-img{
width: 100%;
max-width: 100%;
border: 1px solid blue;
}
.small-img{
border: 1px solid red;
position:absolute;
right: 10%;
top: 10%;
width: 25%;
max-width:25%;
}
<div class="wrapper">
<img class="big-img" src="https://webhostingvirtualdedicatedservers.com/files/2012/09/Web-server.png" />
<img class="small-img" src="http://loosechange.co.za/wp-content/uploads/2012/06/Personal-Discount-10-lg.jpg" />
</div>
So, I want to place a logo right in the middle of a background image which is full page size (height: 100vh). I can do it in about 10 seconds using Elementor, but I have to do it on a website without any CMS, so that's hard for me. I tried literally any snippet I could find online, but it was always about how to stack an image on top of another image, not an image on top of a full-page background.
Here's an example of what I found: https://jsfiddle.net/uu3pqwpa/
I would literally use a background-imagein the CSS for the large container and apply flex settings to it (details see below) to center the smaller img tag within that div (i.e. no absolute/relative positioning, no two img tags):
* {
box-sizing: border-box;
}
html,
body {
margin: 0;
}
.big-img {
width: 100vw;
height: 100vh;
border: 1px solid blue;
position: relative;
background: url('https://placehold.it/2000x1500/fda?text=Background-Image') center center;
background-size: cover;
display: flex;
justify-content: center;
align-items: center;
}
.small-img {
border: 1px solid red;
width: 30%;
height: 25vh;
}
<div class="big-img">
<img class="small-img" src="https://placehold.it/200x100/ab7?text=centered-Image" />
</div>
You could set the background of the wrapper using
background: url('https://webhostingvirtualdedicatedservers.com/files/2012/09/Web-server.png);
keeping it position relative, but adding:
width: 100%;
height: auto;
And then leave the small image positioned absolutely
Placing the images as background images will make it possible to use background-size: cover and have them fit in any size of the container.
Using pseudo-elements, like ::before, is just a way of clear up HTML code with elements that are mostly there for styling.
Any other kind of clarification down below in the code as comments.
html, body {
padding: 0px; /* remove default spacing */
margin: 0px;
}
.wrapper {
position: relative;
min-width: 100vw;
min-height: 100vh; /* min lets the element span beyond the page, if necessary. */
/* didn't find image */
/* background: url('https://webhostingvirtualdedicatedservers.com/files/2012/09/Web-server.png'); */
background: url('https://picsum.photos/200/300');
}
.wrapper, .wrapper::before {
box-sizing: border-box; /* needed to include border size in width and height */
border: 1px solid blue;
background-repeat: none;
background-size: cover;
}
.wrapper::before {
content: '';
position: absolute;
width: 25vw;
height: 25vw; /* make it squarish */
left: 50%;
top: 50%;
/* move element negative 50% of it's own size on both x and y coordinate */
transform: translate(-50%, -50%);
border-color: red;
/* background: url('http://loosechange.co.za/wp-content/uploads/2012/06/Personal-Discount-10-lg.jpg'); */
background: url('https://picsum.photos/200/200');
}
<div class="wrapper">
</div>
.wrapper{
display: flex;
justify-content:center;
align-items:center;
height:100vh;
}
.big-img{
width: 100%;
max-width: 100%;
border: 1px solid blue;
}
.small-img{
border: 1px solid red;
width: 25%;
height:25%;
}
body {
background-image: url("https://images.freeimages.com/images/small-previews/1c9/maine-at-4-45-am-1370871.jpg");
background-size: cover;
}
<div class="wrapper">
<img class="small-img" src="https://images.freeimages.com/images/small-previews/25d/eagle-1523807.jpg"/>
</div>

The top part of the inner element is cut out and unreachable when using a css combination of `position:fixed;` and `display: flex;`

I'm building a fullscreen modal, and I'm trying to center the content vertically when it is smaller than the screen, and to start at the top and allow scroll, when the hight is larger than the hight of the container. I'm trying to use position:fixed to position the container on the screen, and display:flex; align-items:center; to center the inner div. When the container is shorter than the inner div the top part of the inner div is cut out, even when I use: overflow-y:scroll.
Here is my code:
<div class="modal">
<div class="inner-w">
hello world
<div class="long-box">
</div>
</div>
</div>
.modal {
position: fixed;
bottom: 70px;
top: 0;
left:0;
right: 0;
display: flex;
align-items: center;
padding: 15px;
overflow: scroll;
}
.inner-w {
margin: 50px 0;
width: 100%;
}
.long-box {
height: 400px;
width: 100%;
border: 1px solid brown;
}
here is a jsfiddle: https://jsfiddle.net/benCarp/bh2Lfpo4/18/#&togetherjs=aKbe8NLJSR
add to .modal{flex-direction-column;} now you can remove the margin
.modal {
position: fixed;
bottom: 70px;
top: 0;
left:0;
right: 0;
display: flex;
flex-direction:column;
align-items: center;
padding: 15px;
overflow: scroll;
}
.inner-w {
width: 100%;
}
.long-box {
height: 400px;
width: 100%;
border: 1px solid brown;
}
<div class="modal">
<div class="inner-w">
hello world
<div class="long-box">
</div>
</div>
</div>
#godfather had an excellent suggestion to change the direction of the flex container from row to column with .modal{flex-direction-column;}. It better describes our layout, and the width and margin property aren't needed any more. However it is not enough. overflow: scroll (or "auto") property isn't inherited, and should be placed on the actual element that overflows - the .inner-w class.
Here is how the css should look:
.modal {
position: fixed;
flex-direction:column;
bottom: 70px; // kept for a button
top: 0;
left:0;
right: 0;
display: flex;
padding: 15px;
justify-content: center;
}
.inner-w {
overflow: auto;
}
.long-box {
height: 400px;
width: 100%;
border: 1px solid brown;
}

Fill only half of the container with a background color

I have something like this:
#container {
width: 300px;
background-color: red;
display: flex;
justify-content: center;
}
#child {
background-color: green;
width: 250px;
height: 150px;
position: relative;
top: 75px;
}
<div id="container">
<div id="child"></div>
</div>
The red box is the container and it's height is equal to its content - in this case 150px. What I'd like to achieve is to make the container height equal half the size of its content size.
The effect that I want to achieve is to have the background-color fill half of the containers content.
If this can be made in some other way than changing the container height - feel free to propose a solution.
Use a linear gradient:
#child {
background: linear-gradient(to bottom, green 50%, white 0%);
}
change white with body color or any color you want.
Source: CSS-Tricks
You can use gradients here.
Not sure if you want to keep the offset above the green div, but if so, you can also use calc() inside gradients :
add a margin-top: 75px to the child
set background: linear-gradient(red calc(50% + 37px), transparent calc(50% + 37px)) on the parent
This way you don't have to fix any height. Will ease your responsive work afterwards!
#container {
width: 300px;
background: linear-gradient(red 50%, transparent 50%);
display: flex;
justify-content: center;
}
#child {
background-color: green;
}
<div id="container">
<div id="child">
content!<br>
content!<br>
content!<br>
</div>
</div>
Just assign a height to the container and set height: 200%; for the child, like this to make sure the container has half the height of the child:
#container {
width: 300px;
height: 75px;
background-color: red;
display: flex;
justify-content: center;
background-size: 100% 50%;
}
#child {
background-color: green;
width: 250px;
height: 200%;
position: relative;
top: 75px;
}
This is not exactly the way you want to do this, but the result is the same. Maybe it'll help you.
You can make a pseudo element, which has half the height of the container and give it a height 50%;. This way you get a different background-color for half of the container s height.
#container {
width: 300px;
background-color: red;
display: flex;
justify-content: center;
position: relative;
}
#child {
background-color: green;
width: 250px;
height: 150px;
position: relative;
opacity: .5;
top: 75px;
z-index: 1;
}
div#container:after {
content: " Different Color! ";
color: #ffffff;
position: absolute;
width: 100%;
height: 50%;
left: 0;
bottom: 0;
background: blue;
}
<div id="container">
<div id="child"></div>
</div>

CSS Relative children take height of parent

I have a parent div with padding, inside there are 2 children. I want for second child b to take the rest of the height of parent (minus div a). And if div a is not present, than take all height. (with same css!)
#parent {
position: relative;
left: 0;
max-width: 500px;
max-height: 200px;
background: #333;
top: 0;
overflow: hidden;
}
#parent:after {
padding-top: 56.25%;
display: block;
content: '';
}
.a {
position: relative;
height: 20px;
width: 100%;
background: red;
}
.b {
position: relative;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: blue;
overflow: hidden;
}
<div id="parent">
<div class="a">1 </div>
<div class="b">2 </div>
</div>
edit:
why was the question downvoted? What is wrong with the question? how do I ask it without being downvoted?
You can use view-height css unit for div b. Example with your code. If you remove div a you will notice that div b will take all the height.
#parent {
position: relative;
left: 0;
max-width: 500px;
max-height: 200px;
background: #333;
top: 0;
overflow: hidden;
}
#parent:after {
padding-top: 56.25%;
display: block;
content: '';
}
.a {
position: relative;
height: 20px;
width: 100%;
background: red;
}
.b {
position: relative;
top: 0;
left: 0;
width: 100%;
height: 100vh;
background: blue;
overflow: hidden;
}
<div id="parent">
<div class="a">1 </div>
<div class="b">2 </div>
</div>
The intended behaviour can be achieved with flex-box layouts, as demonstrated in the Code Snippet embedded below.
Solution Breakdown:
#parent - declare flex on containing parent element, as well as
flex-wrap so that nested elements can occupy the full-width of the
container, we want to maintain the row direction here.
.a - declare flex-basis on this nested element; which is
tantamount to declaring width: 100% - we want it to remain
full-width so that the following sibling element (.b) wraps to a
new row.
.b - declare the shorthand property flex: 1 1 to specify that
this element should occupy the full width and height of its
containing element but not exceed it. The flex1 property is a
shorthand for flex-shrink2,
flex-grow3, and flex-basis4
#parent {
position: relative;
left: 0;
max-width: 500px;
max-height: 200px;
background: #333;
top: 0;
overflow: hidden;
/* additional */
display: flex;
flex-wrap: wrap;
}
#parent:after {
padding-top: 56.25%;
display: block;
content: '';
}
.a {
position: relative;
height: 20px;
background: red;
/* additional */
flex-basis: 100%;
}
.b {
position: relative;
background: blue;
/* additional */
flex: 1 1;
}
<div id="parent">
<div class="a">1</div>
<div class="b">2</div>
</div>
<br>
<div id="parent">
<div class="b">2</div>
</div>
A note on flex-box:
Since flex-box has limited to no support for legacy browsers (like I.E) for full browser support and compatibility refer to either one of the aforementioned alternatives.
See browser compatibility:
caniuse.com
flex - CSS | MDN
Edit
Updated
#parent {
position: relative;
left: 0;
max-width: 500px;
max-height: 200px;
background: #333;
top: 0;
overflow: hidden;
/* additional */
display: flex;
flex-direction: column;
height: 200px; /* an absolute height value is required for relative flex-box heights */
}
/*#parent:after { kill the interloper
padding-top: 56.25%;
display: block;
content: '';
}*/
.a {
position: relative;
height: 20px;
background: red;
}
.b {
position: relative;
background: blue;
/* additional */
flex: 1 1;
}
<div id="parent">
<div class="a">1</div>
<div class="b">2</div>
</div>
<br>
<div id="parent">
<div class="b">2</div>
</div>
The updated snippet demonstrates an alternative solution with a column direction. The pseudo-element #parent:after has been removed as it negates any attempt to achieve the behaviour specified in your question (if this pseudo-element is required in any shape or form, consider updating your question to point this out with clear explanations as to its function and or role).