Placing elements horizontally or vertically depending on screen size

Hello

I have created a simple webpage in HTML with two elements. The first element is a chat window where users can chat. The second element is a chart.js plot. I have included the HTML and CSS below.

The chart.js plot (<div class="chart-container" id="chart">) is placed to the right of the chat window (<section class="msger">). How can I place the chart.js plot below the chat window? And how can I do this only for certain devices? For larger screen (e.g. desktop screen) it should be placed to the right but for smaller screens (e.g. mobile devices) it should be placed below. The problem here is that the newer mobile devices such as the Samsung S23 Ultra also has a very high resolution, thus using a media query with pixel width for gauging screen size might not work.

The HTML looks as follows:

<!DOCTYPE html>
<html lang="en">
    
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <link rel="shortcut icon" href="#" />
  <link rel="stylesheet" href="{{ url_for('static', filename='styles/style.css') }}">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.2.1/chart.umd.js"></script>
  ...
</head>

<body>
  <section class="msger">
    <header class="msger-header">
       <div class="msger-header-title">
         <!-- Here are several buttons included -->
       </div>
    </header>
    <main class="msger-chat">
        <!-- Here is the main window of the chat -->
        <div class="container" id="start-btn">
	      <button class="start-btn" type="button" onClick="start()">
			Start Conversation
	      </button>
	    </div>
        <div class="msg left-msg">
        </div>
    </main>

    <form class="msger-inputarea" id="msger-input">
       <input type="text" class="msger-input" id="textInput" placeholder="Enter your message..." style="display:none">
       <button type="submit" class="msger-send-btn" style="display:none" id="sendInput">Send</button>
     </form>

  </section>

  <div class="chart-container" id="chart">
        <!-- This is the chart.js plot -->
        <canvas id="myChart"></canvas>
  </div>
</body>

</html>

The CSS file is as follows:

   :root {
    --body-bg: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
    --msger-bg: #fff;
    --border: 2px solid #ddd;
    --left-msg-bg: #ececec;
    --right-msg-bg: #579ffb;
  }

  html {
    box-sizing: border-box;
  }

  *,
  *:before,
  *:after {
    margin: 0;
    padding: 0;
    box-sizing: inherit;
  }

  body {
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
    background-image: var(--body-bg);
    font-family: Helvetica, sans-serif;
  }

  .msger {
    display: flex;
    flex-flow: column wrap;
    justify-content: space-between;
    width: 55%;
    max-width: 55%;
    margin: 25px 10px;
    height: calc(100% - 50px);
    border: var(--border);
    border-radius: 5px;
    background: var(--msger-bg);
    box-shadow: 0 15px 15px -5px rgba(0, 0, 0, 0.2);
    min-width: 55%;
  }

  .msger-header {
    /* display: flex; */
    font-size: medium;
    justify-content: space-between;
    padding: 10px;
    text-align: center;
    border-bottom: var(--border);
    background: #eee;
    color: #666;
  }

  .msger-chat {
    background-color: #fcfcfe;
  }

.container {
      display: flex;
	  align-items: center;
	  justify-content: center;
	  height: 100%;
}

.start-btn {
    background: #239630;
    color: #fff;
    cursor: pointer;
    transition: background 0.23s;
	border: none;
	font-size: xx-large;
	padding: 20px;
	text-align: center;
	border-radius: 20px;
}

.start-btn:hover {
    background: rgb(87, 159, 251);
}

  .msger-inputarea {
    display: flex;
    padding: 10px;
    border-top: var(--border);
    background: #eee;
  }
  .msger-inputarea * {
    padding: 10px;
    border: none;
    border-radius: 3px;
    font-size: 1em;
  }

  .msger-input {
    flex: 1;
    background: #ddd;
  }

  .msger-send-btn {
    margin-left: 10px;
    background: #579ffb;
    color: #fff;
    font-weight: bold;
    cursor: pointer;
    transition: background 0.23s;
  }
  .msger-send-btn:hover {
    background: rgb(0, 180, 50);
  }

.chart-container {
  width: 35%;
  min-width: 35%;
  max-width: 35%;
}

You could use an @media for 500px or less

Thank you very much. For example, my S23 Ultra has a screen resolution of 3088 x 1440, so it would not wrap for this smartphone, although the screen is small and it should wrap. On the other hand, my laptop has a screen resolution of 1920 x 1200 but a much larger screen than my smartphone, thus it should not wrap.

How can this be solved?

And what would you change in the CSS so that it wraps?

Put the two containers inside a flex container with wrapping and limit how much the elements can shrink (so the wrapping kicks in).

Without having the actual content so we know the true size of the elements it is a little hard to give a working example.

.msger {
  width: max(40vw, 420px);
}

.chart-container {
  width: max(40vw, 420px);
}

.flex {
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  column-gap: 2rem;
  flex: 1;
}

Thank you very much, I will give it a try.

So 40vw means 40% of width when I correctly understand. So we have 40% + 40% = 80% covered. Can I also set 50vw for both containers?

Why did you set 420px for the height and not using also “vw”?

There has to be room for the elements to sit side by side so 40vw was just a safe bet.

The other value in the max() function isn’t the height, it is the minimum width. The elements will be whatever 40vw computes to until they shrink down to 420px at which point they will not shrink anymore.


The numbers I used are fairly arbitrary because as I said without the actual content I can’t tell what the best min/max values would be.

Now it is clear, thanks for the clarification. My laptop has a width of 1920 pixels and my Smartphone has a width of 3088 pixels. On my laptop it should not wrap but on my smartphone it should wrap. Is this possible to achieve with this approach as the width of my smartphone is higher than of my laptop?

That seems backward, also the viewport size on a phone is not the same as its pixel size. They have higher pixel density at some rated PPI value.

You might be able to target the resolution or device pixel ratio but what you are describing doesn’t sound correct. I think you might just be misunderstanding how phone screens work.

I can’t really test it besides the browser device mode but this should stack on the iPhone 12 device but not in the normal window.

.flex {
  display: flex;
}

@media (-webkit-device-pixel-ratio: 3) {
  .flex {
    flex-direction: column;
  }
}

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.