Making a Blazor WebAssembly E-commerce Application Responsive with Flexbox

Cenk 1,036 Reputation points
2024-12-31T08:20:29.7566667+00:00

A Blazor WebAssembly e-commerce application has been built, but the design looks good only on a 23-inch 1920x1080 laptop. The layout includes a header, a left navigation menu, and a footer that is consistent across all pages. The goal is to make this layout and the home razor page responsive for all screen sizes without using media queries. Is there a way to achieve this using flexbox?

Screenshot:

Screenshot 2024-12-29 at 20-47-52 Romini

Home.razor:

<link href="css/home.css" rel="stylesheet" />
@if (IsProcessing)
{
    <div class="spinner-overlay">
        <div class="spinner-container">
            <div class="custom-spinner">
                <div></div>
            </div>
            <div class="loading-text">
                Loading for a happy childhood
                <div class="loading-dots">
                    <span>.</span>
                    <span>.</span>
                    <span>.</span>
                </div>
            </div>
        </div>
    </div>
}
else
{
   @if(!Products.Any())
   {
       <section class="py-6 mt-5 mb-5">
           <div class="container bg-light error-section min-vh-50 py-6 d-flex justify-content-center align-items-center" style="max-width:1920px">
               <div class="row">
                   <div class="col-md-12 text-center">
                       <div class="lc-block mb-4">
                           <div editable="rich">
                               <h1 class="fw-bold display-1">404</h1>
                           </div>
                       </div>
                       <div class="lc-block">
                           <div editable="rich">
                               <p class="h2">Sorry, we can’t find the product you’re looking for. </p>
                               <p class="lead">Click the button below to go back to the homepage</p>
                           </div>
                       </div>
                       <div class="lc-block">
                            <a class="btn btn-primary" href="javascript:void(0)" @onclick="() => FetchAllProducts()" role="button">Continue Shopping</a>
                       </div><!-- /lc-block -->
                   </div><!-- /col -->
               </div>
           </div>
       </section>
   }
   else
   {
        <!-- The Modal -->
        <div class="modal bg-transparent @modalClass" id="myModal" tabindex="-1" role="dialog" style="display: @modalDisplay; overflow-y: auto;" aria-hidden="true">
            <div class="modal-dialog modal-dialog-custom">
                <div class="modal-content modal-dialog-centered modal-xl" role="document">
                    <!-- Modal body -->
                    <div class="modal-body custom-search-form p-4">
                        <div class="modal-dialog modal-dialog-centered custom-search-form" role="document">
                            <form @onsubmit="SearchProducts" class="modal-content modal-body custom-search-form">
                                <div class="input-group mb-2">
                                    <input type="text" class="form-control" id="inputModalSearch" @bind="searchTerm" placeholder="Search products...">
                                    <button type="submit" class="btn btn-primary">
                                        <i class="fa fa-fw fa-search"></i>
                                    </button>
                                </div>
                            </form>
                        </div>
                    </div>
                    <!-- Modal footer -->
                    <div class="modal-footer">
                        <button type="button" class="btn btn-danger" data-bs-dismiss="modal" @onclick="CloseModal">Close</button>
                    </div>
                </div>
            </div>
        </div>
        @if (showBackdrop)
        {
            <div class="modal-backdrop fade show"></div>
        }
        <!-- Start Content -->
        <div class="container py-5">
            <div class="row">
                <div class="col-12 col-lg-3">
                    <h1 class="h2 pb-4 text-primary">Categories</h1>
                    <ul class="list-unstyled templatemo-accordion">
                        @foreach (var category in Categories)
                        {
                            <li class="pb-3">
                                <a class="collapsed d-flex justify-content-between h3 text-decoration-none" href="javascript:void(0)" @onclick="() => FetchProductsByCategory(category.Id)">
                                    @category.Name
                                </a>
                            </li>
                        }
                        <li class="pb-3">
                            <a class="collapsed d-flex justify-content-between h3 text-decoration-none" href="javascript:void(0)" @onclick="() => FetchAllProducts()">
                                All
                            </a>
                        </li>
                    </ul>
                    <button type="button" class="btn btn-primary search-button mb-3" @onclick="OpenModal">
                        <i class="fa fa-search me-2"></i>Search
                    </button>
                    <div class="price-slider-container mb-4">
                        <div class="d-flex align-items-center">
                            <span class="price-value">$0</span>
                            <span class="mx-2 flex-grow-1">
                                <input type="range" class="form-range price-slider" 
                                       min="0" max="5000" step="10" 
                                       @bind-value="maxPrice" 
                                       @bind-value:event="oninput"
                                       @onchange="FilterByPrice" />
                            </span>
                            <span class="price-value">$@maxPrice</span>
                        </div>
                    </div>
                </div>
                <div class="col-12 col-lg-9">
                    <div class="row">
                        @foreach (var product in Products)
                        {
                            <div class="col-12 col-sm-6 col-lg-4">
                                <div class="card mb-4 product-wap rounded-0">
                                    <div class="card rounded-0">
                                        <img class="card-img rounded-0 img-fluid product-image" src=@product.ImageUrls.FirstOrDefault()>
                                        <div class="card-img-overlay rounded-0 product-overlay d-flex align-items-center justify-content-center">
                                            <ul class="list-unstyled">
                                                <li>
                                                    <a class="btn btn-primary mt-2" href="ECommerce/ProductDetail/@product.Id" style="border-radius: 25px;">
                                                        <i class="far fa-eye text-white"></i>
                                                    </a>
                                                </li>
                                            </ul>
                                        </div>
                                    </div>
                                    <div class="card-body home-product-card text-center">
                                        <a href="ECommerce/ProductDetail/@product.Id" class="h4 text-decoration-none fw-bold text-dark">@product.Name</a>
                                        <ul class="w-100 list-unstyled d-flex justify-content-center mb-0">
                                            <li class="text-muted">@product.Color</li>
                                        </ul>
                                        <p class="mb-0 product-price text-dark fw-bold">@product.ProductPrices.FirstOrDefault()?.Price.ToString("c")</p>
                                    </div>
                                </div>
                            </div>
                        }
                    </div>
                    @if (Products.Any())
                    {
                        <div class="row">
                            <ul class="pagination pagination-lg justify-content-end">
                                @for (var pages = 1; pages <= CalculateTotalPages(); pages++)
                                {
                                    <li class="page-item">
                                        <a class="page-link @(pages == CurrentPage ? "active" : "") rounded-2 mr-3 shadow-lg border-top-0 border-left-0" href="javascript:void(0)" @onclick="() => SetCurrentPage(pages)">
                                            @pages
                                        </a>
                                    </li>
                                }
                            </ul>
                        </div>
                    }
                    @* <div class="row">
            <ul class="pagination pagination-lg justify-content-end">
            <li class="page-item disabled">
            <a class="page-link active rounded-0 mr-3 shadow-sm border-top-0 border-left-0" href="#" tabindex="-1">1</a>
            </li>
            <li class="page-item">
            <a class="page-link rounded-0 mr-3 shadow-sm border-top-0 border-left-0 text-dark" href="#">2</a>
            </li>
            <li class="page-item">
            <a class="page-link rounded-0 shadow-sm border-top-0 border-left-0 text-dark" href="#">3</a>
            </li>
            </ul>
            </div> *@
                </div>
            </div>
        </div>
        <!-- End Content -->
        <!-- Start Our Story Section -->
        <section class="py-5 our-story-section" style="background-color: #ffdab3;">
            <div class="container my-4">
                <div class="row text-center">
                    <div class="col-lg-8 m-auto">
                        <h1 class="display-4 mb-4" style="color: #FF6B74; font-family: 'Playfair Display', serif;">Our Story</h1>
                        <p class="lead mb-4" style="color: #FF6B74; font-size: 1.2rem; line-height: 1.8;">
                            At Romini Atelier, we believe every child deserves to feel special. Our carefully 
                            crafted collections combine comfort, style, and playfulness to create magical 
                            moments in your little one's everyday adventures.
                        </p>
                        <a href="/ecommerce/AboutRomini" class="btn btn-outline-primary px-4 py-2" style="border-color: #FF6B74; color: #FF6B74; border-radius: 25px; font-size: 1.1rem; transition: all 0.3s ease; background-color: #ffdab3;" onmouseover="this.style.backgroundColor='#FF6B74'; this.style.color='white';" onmouseout="this.style.backgroundColor='#ffdab3'; this.style.color='#FF6B74';">
                            Learn More
                        </a>
                    </div>
                </div>
            </div>
        </section>
        <!-- End Our Story Section -->
        <!-- Start Brands -->
        <section class="bg-light py-5 brands-section">
            <div class="container my-4">
                <div class="row text-center py-3">
                    <div class="col-lg-6 m-auto">
                        <h1 class="h1">Our Brands</h1>
                        <p>
                            Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
                            Lorem ipsum dolor sit amet.
                        </p>
                    </div>
                    <div class="col-lg-9 m-auto tempaltemo-carousel">
                        <div class="row d-flex flex-row">
                            <!--Controls-->
                            <div class="col-1 align-self-center">
                                <a class="h1" href="#multi-item-example" role="button" data-bs-slide="prev">
                                    <i class="text-light fas fa-chevron-left"></i>
                                </a>
                            </div>
                            <!--End Controls-->
                            <!--Carousel Wrapper-->
                            <div class="col">
                                <div class="carousel slide carousel-multi-item pt-2 pt-md-0" id="multi-item-example" data-bs-ride="carousel">
                                    <!--Slides-->
                                    <div class="carousel-inner product-links-wap" role="listbox">
                                        <!--First slide-->
                                        <div class="carousel-item active">
                                            <div class="row">
                                                <div class="col-3 p-md-5">
                                                    <a href="#">
                                                        <img class="img-fluid brand-img" src="images/ecommerce/brand_01.png" alt="Brand Logo">
                                                    </a>
                                                </div>
                                                <div class="col-3 p-md-5">
                                                    <a href="#">
                                                        <img class="img-fluid brand-img" src="images/ecommerce/brand_02.png" alt="Brand Logo">
                                                    </a>
                                                </div>
                                                <div class="col-3 p-md-5">
                                                    <a href="#">
                                                        <img class="img-fluid brand-img" src="images/ecommerce/brand_03.png" alt="Brand Logo">
                                                    </a>
                                                </div>
                                                <div class="col-3 p-md-5">
                                                    <a href="#">
                                                        <img class="img-fluid brand-img" src="images/ecommerce/brand_04.png" alt="Brand Logo">
                                                    </a>
                                                </div>
                                            </div>
                                        </div>
                                        <!--End First slide-->
                                        <!--Second slide-->
                                        <div class="carousel-item">
                                            <div class="row">
                                                <div class="col-3 p-md-5">
                                                    <a href="#">
                                                        <img class="img-fluid brand-img" src="images/ecommerce/brand_01.png" alt="Brand Logo">
                                                    </a>
                                                </div>
                                                <div class="col-3 p-md-5">
                                                    <a href="#">
                                                        <img class="img-fluid brand-img" src="images/ecommerce/brand_02.png" alt="Brand Logo">
                                                    </a>
                                                </div>
                                                <div class="col-3 p-md-5">
                                                    <a href="#">
                                                        <img class="img-fluid brand-img" src="images/ecommerce/brand_03.png" alt="Brand Logo">
                                                    </a>
                                                </div>
                                                <div class="col-3 p-md-5">
                                                    <a href="#">
                                                        <img class="img-fluid brand-img" src="images/ecommerce/brand_04.png" alt="Brand Logo">
                                                    </a>
                                                </div>
                                            </div>
                                        </div>
                                        <!--End Second slide-->
                                        <!--Third slide-->
                                        <div class="carousel-item">
                                            <div class="row">
                                                <div class="col-3 p-md-5">
                                                    <a href="#">
                                                        <img class="img-fluid brand-img" src="images/ecommerce/brand_01.png" alt="Brand Logo">
                                                    </a>
                                                </div>
                                                <div class="col-3 p-md-5">
                                                    <a href="#">
                                                        <img class="img-fluid brand-img" src="images/ecommerce/brand_02.png" alt="Brand Logo">
                                                    </a>
                                                </div>
                                                <div class="col-3 p-md-5">
                                                    <a href="#">
                                                        <img class="img-fluid brand-img" src="images/ecommerce/brand_03.png" alt="Brand Logo">
                                                    </a>
                                                </div>
                                                <div class="col-3 p-md-5">
                                                    <a href="#">
                                                        <img class="img-fluid brand-img" src="images/ecommerce/brand_04.png" alt="Brand Logo">
                                                    </a>
                                                </div>
                                            </div>
                                        </div>
                                        <!--End Third slide-->
                                    </div>
                                    <!--End Slides-->
                                </div>
                            </div>
                            <!--End Carousel Wrapper-->
                            <!--Controls-->
                            <div class="col-1 align-self-center">
                                <a class="h1" href="#multi-item-example" role="button" data-bs-slide="next">
                                    <i class="text-light fas fa-chevron-right"></i>
                                </a>
                            </div>
                            <!--End Controls-->
                        </div>
                    </div>
                </div>
            </div>
        </section>
        <!--End Brands-->
   }    
}


Home.css:

.price-value {
    font-size: 0.9rem;
    color: #666;
    min-width: 55px;
}
.price-slider {
    height: 4px;
    -webkit-appearance: none;
    appearance: none;
}
/* Webkit (Chrome, Safari, Edge) */
.price-slider::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    background: #FF6B74;
    width: 16px;
    height: 16px;
    border: none;
    border-radius: 50%;
    cursor: pointer;
}
/* Firefox */
.price-slider::-moz-range-thumb {
    background: #FF6B74;
    width: 16px;
    height: 16px;
    border: none;
    border-radius: 50%;
    cursor: pointer;
}
/* IE */
.price-slider::-ms-thumb {
    background: #FF6B74;
    width: 16px;
    height: 16px;
    border: none;
    border-radius: 50%;
    cursor: pointer;
}
.price-slider::-webkit-slider-runnable-track {
    background: #dee2e6;
    height: 4px;
    border-radius: 2px;
}
.price-slider::-moz-range-track {
    background: #dee2e6;
    height: 4px;
    border-radius: 2px;
}
.price-slider::-ms-track {
    background: #dee2e6;
    height: 4px;
    border-radius: 2px;
}
/* Mobile First Styles (default: < 576px) */
.container {
    padding: 1rem;
}
.col-lg-3 {
    margin-bottom: 2rem;
}
.h2.pb-4 {
    font-size: 1.5rem;
    padding-bottom: 0.5rem !important;
}
.collapsed.h3 {
    font-size: 1.1rem;
    padding: 0.5rem 0;
}
.search-button {
    width: 100% !important;
}
.card.mb-4 {
    margin-bottom: 1rem !important;
}
.product-image {
    height: 200px;
    object-fit: cover;
}
.pagination-lg .page-link {
    padding: 0.5rem 0.75rem;
    font-size: 0.9rem;
}
/* Small devices (tablets, 576px and up) */
@media (min-width: 576px) {
    .container {
        padding: 1.5rem;
    }
    .card.mb-4 {
        margin-bottom: 1.5rem !important;
    }
    .product-image {
        height: 250px;
    }
}
/* Medium devices (768px and up) */
@media (min-width: 768px) {
    .container {
        padding: 2rem;
    }
    .h2.pb-4 {
        font-size: 1.8rem;
    }
    .collapsed.h3 {
        font-size: 1.2rem;
    }
    .product-image {
        height: 300px;
    }
}
/* Large devices (desktops, 992px and up) */
@media (min-width: 992px) {
    .container {
        padding: 3rem;
    }
    .search-button {
        width: 50% !important;
    }
    .h2.pb-4 {
        font-size: 2rem;
        padding-bottom: 1.5rem !important;
    }
    .collapsed.h3 {
        font-size: 1.3rem;
    }
    .col-lg-3 {
        margin-bottom: 0;
    }
}
/* Extra large devices (1200px and up) */
@media (min-width: 1200px) {
    .product-image {
        height: 350px;
    }
}
/* Additional Mobile Fixes for 320px-480px */
@media (max-width: 480px) {
    .atelier-text {
        font-size: 3.2rem !important;
        white-space: nowrap;
    }
    .navbar-toggler-icon {
        font-size: 1.2rem;
    }
    .footer-logo {
        font-size: 3.2rem !important;
        word-break: break-word;
        hyphens: auto;
    }
    .brand-container {
        padding: 0.5rem;
    }
    /* Navbar mobile styles */
    .navbar-collapse {
        position: absolute;
        top: 100%;
        left: 0;
        right: 0;
        background: white;
        z-index: -1;
        padding: 1rem;
        box-shadow: 0 2px 5px rgba(0,0,0,0.1);
        display: none !important;
    }
    .navbar-collapse.show-menu {
        display: block !important;
        z-index: 1000;
    }
    .navbar-nav {
        padding-top: 0.5rem;
    }
    .nav-item {
        padding: 0.5rem 0;
    }
    /* Remove all Bootstrap collapse classes */
    .collapse,
    .collapsing,
    .show {
        display: none !important;
    }
    .show-menu {
        display: block !important;
    }
    /* Ensure toggler stays above */
    .navbar-toggler {
        position: relative;
        z-index: 1001;
    }
    /* Remove all transitions */
    .navbar,
    .navbar *,
    .navbar-collapse,
    .navbar-collapse * {
        transition: none !important;
        -webkit-transition: none !important;
        animation: none !important;
    }
}
/* Small devices fixes */
@media (max-width: 576px) {
    .footer-logo {
        font-size: 3.2rem;
    }
    .navbar-brand {
        font-size: 3.2rem;
    }
} 
Developer technologies | ASP.NET | ASP.NET Core
Developer technologies | .NET | Blazor
0 comments No comments
{count} votes

3 answers

Sort by: Most helpful
  1. Bruce (SqlWork.com) 79,101 Reputation points Volunteer Moderator
    2024-12-31T16:54:26.0333333+00:00

    Well on a mobile you probably want only one column, not 3, and the menu should be fly out or similar. You can do this with css media queries and some blazor/javascript support, or all in blazor/javascript.

    you can use responsive design, or based on screen size and orientation, pick a custom layout, say phone, tablet or computer.

    note: for a ecomm site, you should look at pre-render for blazor WASM to mitigate the load time.

    0 comments No comments

  2. Raymond Huynh (WICLOUD CORPORATION) 620 Reputation points Microsoft External Staff
    2025-07-16T08:42:37.4633333+00:00

    Hello Cenk,

    You can get a lot of responsiveness using Flexbox and Bootstrap’s grid system, but for perfect control (like changing the sidebar to a drawer on mobile), media queries or a framework’s built-in breakpoints are usually needed. However, you can achieve a surprisingly good result with just Flexbox and Bootstrap’s classes, which themselves use media queries under the hood.

    Here are my recommendations:

    1. Use Bootstrap’s Grid and Flex Utilities

    Bootstrap’s grid system is built on Flexbox and is mobile-first.

    When you use classes like col-12 col-sm-6 col-lg-4, you’re already leveraging Flexbox and built-in breakpoints, no custom media queries needed.

    Example for your product cards:

    <div class="row">
    <div class="col-12 col-sm-6 col-lg-4">
    <!-- Product card -->
    </div>
    <!-- ...repeat for each product -->
    </div>
    
    • On mobile: 1 column
    • On tablet: 2 columns
    • On desktop: 3 columns

    2. Sidebar and Main Content with Flexbox

    You can use Flexbox to lay out your sidebar and main content.

    Here’s a pure Flexbox approach (no media queries):

    <div class="d-flex flex-wrap">
    <aside class="flex-shrink-0" style="min-width:220px;">
    <!-- Sidebar content -->
    </aside>
    <main class="flex-grow-1">
    <!-- Main content -->
    </main>
    </div>
    
    • On wide screens, sidebar and main content are side by side.
    • On narrow screens, flex-wrap makes them stack vertically.

    3. Flexbox for Product Cards

    To make product cards wrap and fill the space responsively:

    <div class="d-flex flex-wrap justify-content-center">
    <div class="product-card m-2" style="flex: 1 1 300px; max-width: 350px;">
    <!-- Card content -->
    </div>
    <!-- ...repeat for each product -->
    </div>
    
    
    • flex: 1 1 300px; means each card will try to be at least 300px wide, but will shrink/grow as needed.
    • Cards will wrap to the next line automatically as the screen gets smaller.

    4. No Custom Media Queries Needed

    All of the above works without you writing a single media query.

    You’re using Flexbox’s natural wrapping and Bootstrap’s grid (which uses its own media queries internally, but you don’t have to write them).

    Limitations:

    • If you want to radically change the layout (like turning the sidebar into a hamburger menu on mobile), you’ll need either JavaScript or media queries.
    • For most e-commerce layouts, Flexbox and Bootstrap’s grid will get you 90% of the way there.

    Hope this helps!


  3. Devang Prajapati 0 Reputation points
    2025-07-24T11:56:14.55+00:00
    1. Use a Top-Level Flex Layout
      1. Structure your layout with <div class="layout-root"> as a flex container in column direction:
              <div class="layout-root">
              <header class="header">Header</header>
              <div class="layout-main">
                <nav class="sidebar">Sidebar</nav>
                <main class="content">Main Content</main>
              </div>
              <footer class="footer">Footer</footer>
              </div>
        
    2. CSS with Flexbox (No Media Queries)
      1.       html, body {
                  height: 100%;
                  margin: 0;
                  font-family: sans-serif;
              }
              .layout-root {
                  display: flex;
                  flex-direction: column;
                  height: 100vh;
              }
              .header, .footer {
                  background: #333;
                  color: white;
                  padding: 1rem;
                  text-align: center;
                  flex-shrink: 0;
              }
              .layout-main {
                  display: flex;
                  flex: 1;
                  overflow: hidden;
              }
              .sidebar {
                  background: #eee;
                  min-width: 200px;
                  max-width: 250px;
                  flex: 0 0 auto;
                  padding: 1rem;
                  overflow-y: auto;
              }
              .content {
                  flex: 1;
                  padding: 1rem;
                  overflow-y: auto;
                  min-width: 0;
              }
        
    3. Make Sidebar Behave Flexibly (Auto-wrap on small screens) - Add flex-wrap so content and sidebar stack when screen is tight:
      1.       .layout-main {
                  display: flex;
                  flex: 1;
                  flex-wrap: wrap; /* enables wrap on small screens */
              }
        
    4. Ensure Min/Max Widths Are Used Wisely
      1.       .sidebar {
                  min-width: 150px;
                  max-width: 250px;
              }
              .content {
                  min-width: 200px;
              }
        
    5. Use MudBlazor or Bootstrap
      1. If you're using MudBlazor, use:
              <MudGrid>
                <MudItem xs="12" md="3"> <!-- Sidebar -->
                <MudItem xs="12" md="9"> <!-- Main content -->
              </MudGrid>
        
    6. Test on Different Devices
      1. Use browser DevTools > Responsive Design Mode to test widths like:
        • 320px (Mobile)
        • 768px (Tablet)
        • 1024px (Laptop)
        • 1440px+ (Desktop)
      Use % Instead of Fixed px

    Happy coding and designing :)

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.