I am trying to centrally position a modal whose button is clicked in grid column 2. Can anyone please point me in the right direction. I wouldn't want to hard code any margins ofcourse (responsive).
Right now it (green div) is only showing up / restricted to grid-column 2 as seen below .
display: grid;
grid-template-columns: 1fr 1fr;
height: 100%;
margin: 10px;
class Login extends Component {
state = {
isShowModal: false
};
openModal = () => {
this.setState({ isShowModal: true })
}
render() {
const { isShowModal } = this.state;
return (
<>
<div className="grid-1">
</div>
<div className="grid-2">
{isShowModal && <Modal />}
<div className="add">
<button onClick={() => this.openModal()} type="button">Open modal</button>
</div>
</div>
</>
)
}
}
Hi I think what you are looking for is Width max-content with some padding and margin 0px auto.
margin: 0px auto;
width: max-content;
padding: 10px;
max-width:100%; //for responsive purposes.
Then make a surrounding div and position it fixed. And apply the above styles to the divs inside your surrounding div
What this is doing is making a surrounding div that you can design your stuff inside of that will be centered.
Side Note: If you div is falling underneath other elements just set the z-index to 1.
z-index:1;
Related
I'm using flexbox to display several 3-4 widgets in a single vertical column. Each widget contains a table with a dynamic number of fixed-height rows. I'm trying to accomplish the following:
Widgets should auto-size to their content (remaining as small as possible) (flex-basis:auto)
Widgets should not grow (never appear larger than their content) (flex-grow:0)
Widgets should shrink (showing scrollbars) when the parent container is full (flex-shrink:>0)
Widgets should shrink relative to the size of their content (larger widgets should shrink more than smaller widgets) (flex-shrink:items.length)
Unfortunately, I'm having trouble with the last objective. I've tried using the item count as a value for flex-shrink, assuming it would shrink each widget relatively based on the number of items it contained. However, this doesn't work and leads to some strange/unexpected behavior.
Below is a code snippet demonstrating the issue (JSFiddle here: https://jsfiddle.net/87uwfkv3/5/). In this case (4 widgets of varying sizes) I'd like the second widget to show a single row (since it's only a single item), and the other 3 widgets to be (approximately) the same pixel height as one another with scrollbars.
const App = () => (
<div className="root">
<Widget count={60} />
<Widget count={1} />
<Widget count={600} />
<Widget count={40} />
</div>
);
const Widget = ({ count }) => (
<div className="widget" style={{flexShrink: count}}>
{new Array(count).fill(0).map((o,i) => (
<div key={i}>
item {i+1}
</div>
))}
</div>
);
ReactDOM
.createRoot(document.body)
.render(<App />);
html, body {
background: #aaa;
padding: 5px;
}
.root {
background-color: #ccc;
display: flex;
flex-direction: column;
height: 200px;
gap: 5px;
}
.widget {
background-color: #fff;
border: 1px solid black;
flex: 0 1 auto;
overflow-y: auto;
width: 200px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.development.js"></script>
I have this problem where if I click on an item, all the items in that column gets affected by the click. I want only that very item where I clicked to have the class. but in my code, all the other items of that column are getting the class when I click on a certain single item. I want to make a div go fullscreen when I click on that particular div. kinda like modal pop up, here I want that the div slowly animates to fullscreen
export default class App extends React.Component {
constructor(props) {
super(props);
this.addActiveClass = this.addActiveClass.bind(this);
this.state = {
activeIndex: -1
};
}
addActiveClass(activeIndex) {
this.setState(prev => ({
activeIndex: prev.activeIndex === activeIndex ? -1 : activeIndex
}));
}
render() {
return (
<div className="container">
{Array.from({ length: 30 }).map((item, index) => {
return (
<div
key={index}
style={{
background: randomColor(colors),
height: randomHeight(100, 200)
}}
className={this.state.activeIndex === index ? "full" : ""}
onClick={() => this.addActiveClass(index)}
/>
);
})}
</div>
);
}
}
* {
box-sizing: border-box;
}
body {
margin: 40px;
background-color: #fff;
color: #444;
font: 2em Sansita, sans-serif;
}
.container {
display: flex;
flex-direction: column;
flex-wrap: wrap;
max-height: 100vh;
}
.container > * {
border: 2px solid orange;
border-radius: 5px;
margin: 10px;
padding: 10px 20px;
background-color: red;
color: #fff;
}
.full{
width: 100%;
height: 100%;
transition: 2s;
}
sandbox demonstrating the problem
I don't know exactly what kind of effect you would like to achieve with the selected item but items in the column are affected because of the default value of flexbox align-items which is stretch. The other items are stretching to match the selected element. Try to add align-items: flex-start to your .container class.
You'll have to make sure you're adding the class to the event target. Your onClick function needs to take the event as one of it's arguments, and you need to use event.target in the function body to make sure you're only affecting the element that is clicked. Hope that makes sense!
https://developer.mozilla.org/en-US/docs/Web/API/Event/target
The class adding logic works ok. You can observe this by checking the elements on developer tools. The problem is you are adding an inline style to your elements.
style={{
background: randomColor(colors),
height: randomHeight(100, 200)
}}
So, after each new render, this overrides the full class and give new height and new color.
The other problem is your full class. You are using 100% for height and width and probably this causes problems for your flex.
Just remove the inline style part and instead of using a percentage give custom width and height to full class, then you can see adding the class logic works well.
Pass down an event (e) from your onClick, then access that specific item through e.target.className. This way only the clicked item is updated, even if dynamically rendered from an array:
handleClick = e => { e.target.classNamme = 'class' }
<div className='' onClick={e => handleClick(e)}></div>
Alternatively, if you're keeping your classes in the state, you can just replace the string value with your variable and control in inside the function, as you've done in the example you've provided.
Adding !important overrides the inline-style height.
Height is set to 100vh to expand the div into full screen.
.full{
width: 100%;
height: 100vh !important;
transition: 2s;
}
I created a carousel similar to the one on Instagram that is working, but I realized that if I move the scroll y of the parent element before the scroll x movement of the child element ends it will not end.
gif of the example below ...
note: sorry for bad English, not my native language.
code
.container {
width: 100%;
display: flex;
flex-direction: column;
overflow-y: scroll;
.x {
margin-top: 30px;
display: flex;
overflow-x: scroll;
scroll-snap-type: x mandatory;
div {
flex: 0 0 auto;
scroll-snap-align: start;
width: 100vw;
height: 100vw;
}
.x-item1 {
background: green;
}
.x-item2 {
background: blue;
}
}
}
<Container>
<div className="x">
<div className="x-item1" />
<div className="x-item2" />
</div>
... other divs
</Container>
--->> Example Gif !! <<---
I found a solution that, in my opinion, meets my proposal without losing the performance of the functionality ...
I just thought that there could be a delay in scrollIntoView, like "behavior: smooth" ...
https://developer.mozilla.org/pt-BR/docs/Web/API/Element/scrollIntoView
but it didn't work if someone wants to add an improvement, thanks.
in the container I put an "onTouchStart"
<Container className="works" onTouchStart={() => handleCarousel()} >
<div className="x">
<div className="x-item1" />
<div className="x-item2" />
</div>
... other divs
</Container>
function handleCarousel...
const handleCarousel = () => {
const works = Array.from(document.querySelectorAll('.work-content'));
const carousels = Array.from(document.querySelectorAll('.work-carousel'));
carousels.forEach(carousel => {
if (carousel.scrollLeft % window.innerWidth !== 0) {
const item = document.querySelector(
`.work-content:nth-child(${
works.indexOf(carousel.parentElement) + 1
}) > div.work-carousel > img.work-carousel-item-active`,
); // in another function I already control which image is being viewed and add this class
const scroll = document.querySelector('.works').scrollTop; // optional: get vertical scroll value
item.scrollIntoView(); // horizontal scrolling gains focus
document.querySelector('.works').scrollTop = scroll; // optional: returns vertical scroll value
}
});
};
I believe this is the expected behavior; scrolling in one direction interrupts scrolling in the other, even scrolling that's declared manditory by Scroll Snap CSS attributes.
If you dislike this behavior, you might use a JS-based animation that programmatically scrolls the container horizontally, since this won't be affected by vertical scrolling.
Sorry I can't help more.
I'm trying to build an image viewer with specific requirements. They are as follows:
The content area is a grid-area.
If the image is larger than the content area, it should be contained without stretching the image.
If the image is smaller than the content area, it should be centred within the content area.
There must be a div tightly wrapping the image at all times.
I've made a quick sketch below illustrating the desired behaviour for a portrait (top row), and landscape (bottom row). The images on the left column are the behaviour required if the image's resolution is higher than the content area.
Color code:
White box: content area.
Red box: image.
Blue border: image
wrapping div.
My primary approach so far has been to absolutely position the wrapping div around the image, which works fine until I try to get the resize to fit behaviour in. Usually this will break the tightly wrapped div.
I can also use Javascript, but because this is a foundation to build more on top of I'd rather try keep it to HTML and CSS.
You should ensure that your div just assumes the size of the content, the img in this case. So don't use absolute. You mentioned using grid, so the below example will generate the a grid with a main section wrapped by 20px padding. Then just use the max value on the img to make sure it does exceed the grid box's size. Then center it within the grid box:
const width = document.querySelector( '[name=width]' );
const height = document.querySelector( '[name=height]' );
const image = document.querySelector( 'img' );
function onchange(){
image.src = `http://placehold.it/${width.value}x${height.value}`;
image.style = '';
}
width.addEventListener( 'change', onchange );
height.addEventListener( 'change', onchange );
window.addEventListener( 'DOMContentLoaded', () => setTimeout( onchange, 100 ) );
body, html { height: 100%; }
body { padding: 0; margin: 0; }
main {
display: grid;
grid-template: "left top right" 20px "left main right" 1fr "left bottom right" 20px / 20px 1fr 20px;
height: 100%;
}
main div {
grid-area: main;
border: 1px solid red;
display: inline;
align-self: center;
justify-self: center;
}
main div img {
max-width: 100%;
max-height: 100%;
display: block;
}
#inputs {
position: absolute;
top: 0;
left: 0;
transform: translateY(-100%);
transition: transform .4s;
width: 100%;
padding: 10px;
background: black;
color: white;
}
body:hover #inputs {
transform: translateY(0);
}
<main>
<div>
<img />
</div>
</main>
<div id="inputs">
<label>Width: <input name="width" value="200" type="number" /></label>
<label>Height: <input name="height" value="200" type="number" /></label>
</div>
I have included some javascript so you can test out different sizes of image. I added a img.style = '' to trigger a CSS recalculate after adding the new image, otherwise its size will be incorrect on load.
This is probably going to be a long one:
I'm trying to make a chat application (similar to Slack) with Electron, React and Socket.io. My issue is mostly dealing with React and CSS/Sass though. Right now I've got a few bootstrap, but I'm not really using the grid system at all, so that can/may be scrapped.
The structure of the page is as follows: I've got a footer with a resizable textarea. above it I've got a div that will be holding messages. That div has overflow-y set to scroll, that way the scrollbar is only for the messages and doesn't take the entire page's space. I want the div to get shorter as the footer grows with the textarea. Right now though the div just extends under the footer (and the scrollbar along with it). Since the messages fill the div there's nothing to scroll and no thumb (I think that's the correct term) in the scrollbar.
React component (I've only included one li for the sake of brevity, but in my code I've got bunch):
import React from 'react';
import { Button, Image, Media, Panel } from 'react-bootstrap';
export default class Page extends React.Component {
constructor(props) {
super(props);
this.state = props;
}
footerResize() {
// code to resize messages div, or at least get some information about
// the footer's height
}
render() {
return (
<div className="page">
<div className="sidebar">
</div>
<div className="container-fluid">
<div classname="messages">
<ul>
<li className="message>
<Media>
<Media.Left>
<Image src="#" />
</Media.Left>
<Media.Body>
<Media.Heading>
Name
</Media.Heading>
Message content
</Media.Body>
</Media>
<li>
</ul>
</div>
<footer>
<textarea defaultValue="test text" />
</footer>
</div>
</div>
);
}
}
_page.scss (most of this is from the file name _page.scss but a few properties are pulled in from other files here so I'm only typing one file's contents):
$dark-grey: #383838;
$default-font-color: #FFFFFF;
$light-grey: #474747;
$light-light-grey: #908E8F
$sidebar-width: 250px;
body {
color: $default-font-color;
overflow: hidden;
}
ul {
list-style: none;
}
.page {
background-color: $light-grey;
height: 100vh;
.sidebar {
background-color: $light-light-grey;
position: fixed;
height: 100%;
width: $sidebar-width;
.container-fluid {
margin-left: $sidebar-width;
padding-left: 0px;
padding-right: 0px;
.messages {
overflow-y: scroll;
}
footer {
background-color: $main-green;
bottom: 0;
padding-bottom: 10px;
padding-left: 10px;
padding-right: 10px;
padding-top: 10px;
position: fixed;
width: calc(100% - #{$sidebar-width});
}
}
}
}
I've tried a bunch of different things to get this to work. I've tried a few node modules. I've tried adding event listeners both by adding ref='footer' to the footer and referring to it as this.refs.footer in when adding the event listener and by giving footer and id and using document.getElementById('footer'). The whatever I try I can't get any information about the footer's size in the footerResize. Any help on this would be appreciated. I don't even know if this is something I should be doing with sass properties or whether I need js/React to do this.
You can try out a flexbox based layout.
This for .container-fluid
display: flex;
flex-direction: column;
This for .messages
flex: 1;
Then you remove position: fixed from footer
What this does: it sets the height of .messages to fill its parent's remaining space. So when footer gets bigger, there is less remaining space and .messages will shrink.
Please note that you will need to add vendor prefixes for flexbox depending on your targeted browser support.