0

I am creating a web application for my react-native application. I feel quite comfortable in styling on react-native and was trying to use flexbox on the web also hoping it would allow me to use my react-native knowledge. But the styles behave a little differently on the web and I am having a hard time finding a good resource that explains the basics. I understand the meaning of each flexbox properly but there is a gap in my understanding due to which I am not able to achieve the desired layout.

Please refer to the following code snippet. Link to code sandbox also below the snippet.

import React, { useState } from "react";
import ReactDOM from 'react-dom';
import { Box, Header, Text, Avatar, Menu, List } from "grommet";
import { MoreVertical } from "grommet-icons";

const AlarmDetailsHeader = () => {
  return (
    <Header className="alarmDetailsHeader" background="brand" pad="small">
      <Text>"alarm1"</Text>
      <Menu icon={<MoreVertical />} items={[{ label: "logout" }]} />
    </Header>
  );
};

const AlarmDetails = (props) => {
  return (
    <Box className="alarmDetails" flex={true}>
      <AlarmDetailsHeader />
      <Box flex={true} />
    </Box>
  );
};

const AlarmSummary = (item, index, state) => {
  return (
    <Box margin="medium">
      <Text>{item.name}</Text>
    </Box>
  );
};

const AlarmListHeader = (props) => (
  <Header className="alarmListHeader" background="brand" pad="small" border="right">
    <Avatar src="//s.gravatar.com/avatar/b7fb138d53ba0f573212ccce38a7c43b?s=80" />
    <Text level={5}>"Alarms</Text>
    <Menu
      icon={<MoreVertical />}
      items={[
        { label: "First Action", onClick: () => {} },
        { label: "Second Action", onClick: () => {} }
      ]}
    />
  </Header>
);

const AlarmList = () => {
  const [alarms, setAlarms] = useState([
    {
      name: "alarm1"
    },
    {
      name: "alarm2"
    }
  ]);
  return (
    <Box className="alarmList" fill="vertical">
      <AlarmListHeader />
      {/* <List data={alarms} children={AlarmSummary} /> */}
    </Box>
  );
};

const App = () => {
  return (
    <Box className="alarmListWithDetails" direction="row" flex={true}>
      <AlarmList />
      <AlarmDetails />
    </Box>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  rootElement
);
.App {
  font-family: sans-serif;
  text-align: center;
}

.routerContainer {
  display: flex;
  height: "100vh";
  width: "100vw";
  justify-content: center;
}

.alarmListWithDetails {
  max-width: "1080px";
}

.alarmList {
  background-color: ivory;
  width: "320px";
}

.alarmDetails {
  background-color: antiquewhite;
}

.alarmListHeader {
  height: '80px'
}

.alarmDetailsHeader {
  height: '80px'
}
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="theme-color" content="#000000">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/grommet/2.16.2/grommet.min.js"></script>
    <!--
      manifest.json provides metadata used when your web app is added to the
      homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
    -->
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json">
    <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
    <!--
      Notice the use of %PUBLIC_URL% in the tags above.
      It will be replaced with the URL of the `public` folder during the build.
      Only files inside the `public` folder can be referenced from the HTML.

      Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
      work correctly both with client-side routing and a non-root public URL.
      Learn how to configure a non-root public URL by running `npm run build`.
    -->
    <title>React App</title>
  <style type="text/css">
      body {
        margin: 0;
      }
      #root {
        height: 100vh;
        width: 100vw;
        background-color: lightblue;
      }
    </style>
</head>

<body>
    <noscript>
        You need to enable JavaScript to run this app.
    </noscript>
    <div id="root"></div>
    <!--
      This HTML file is a template.
      If you open it directly in the browser, you will see an empty page.

      You can add webfonts, meta tags, or analytics to this file.
      The build step will place the bundled scripts into the <body> tag.

      To begin the development, run `npm start` or `yarn start`.
      To create a production bundle, use `npm run build` or `yarn build`.
    -->
</body>

</html>

https://codesandbox.io/s/alarm-web1-yztws?file=/src/styles.css

I am trying to achieve the below layout which is similar to the Whatsapp Web layout.

enter image description here

This is what I am getting at the moment:

enter image description here

I want to assign a max-width for the main window but that doesn't seem to take effect. I want the sidebar of the left to cover the full height of the window for which I tried using different CSS properties such as height: '100%' or fill: vertical or flex: 1 but that doesn't have any effect either.

Similarly, I want the details panel to take the complete height. I want the height of both the headers to be the same for which I specified height: 80px but that doesn't seem to have any effect either. These things work quite easily on mobile but for some reason, the web doesn't work the same.

I found flexboxfroggy.com and finished all the levels but as I mentioned, I understand the flexbox properties but the web requires some more things than just the flexbox properties to get the layout right.

Varun Gupta
  • 2,870
  • 6
  • 33
  • 73
  • 1
    Please add your CSS to the question itself (not just a link to it); Stack Overflow requires this, and it does have a sandbox option in the post editor you can add your code to so that it is runnable. – TylerH Dec 28 '20 at 16:16
  • you can see this example (using bootstrap) https://startbootstrap.com/previews/simple-sidebar, – MahmouD Skafi Dec 28 '20 at 17:44
  • Why don't you use CSS Grid? – AbsoluteBeginner Dec 28 '20 at 17:48
  • I am familiar with flexbox as I am already using it in the react-native application and I was hoping I could even reuse some of the styles as I am porting the mobile application to the web. – Varun Gupta Dec 28 '20 at 18:40
  • I see. Anyway, if you decide to get close to CSS Grid, this is a good starting point (and there you'll find exactly what you're after): https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Grid_Template_Areas – AbsoluteBeginner Dec 28 '20 at 19:12
  • Hi @VarunGupta, looks like your codesandbox no longer reproduces the issue, does it mean you were able to solve it? BTW, super call to see you are posting my avatar on the snapshot :) Let me know if I can help with anything. – Shimi Jan 06 '21 at 21:43
  • hi @Shimi, being very new to CSS and coming from `react-native`, I made a mistake of specifying all the width and height values as strings delimited by quotes instead of just the values for e.g. `'100%'` instead of `100%` which was causing all the issues. There were no warnings or errors regarding the wrong values and I had no idea they should be without the quotes. – Varun Gupta Jan 10 '21 at 12:08

1 Answers1

1

Your CSS is causing some issues, but essentially you need to look at how parent and children selection works. You need to do a reset at the top level to allow 100% for child elements below it. The 100% should be working but it is set at the HTML/BODY level first. Similar with Flex, it needs to be set at a parent level before the children can display in the manner you set. Then you can use something like flex-direction: column; which will then create a whole column and then any div inside that you set to flex: 1 and you'll get a full height. You can read more here.

I wouldn't recommend using the VH or VW as they only fill the window in its current state. If that window changes then the selection will remain the previous dimension only.

An example from your CSS above is below, I've removed code that isn't working and added some.

html, body {
  height: 100%;
}

body {
  display: flex;
}

.App {
  font-family: sans-serif;
  text-align: center;
}

.routerContainer {
  justify-content: center;
}

.alarmListWithDetails {
  max-width: 1080px;
}

.alarmList {
  background-color: ivory;
  width: 320px;
}

.alarmDetails {
  background-color: antiquewhite;
}

.alarmListHeader {
  height: 80px;
}

.alarmDetailsHeader {
  height: 80px;
}