Making a Blazor WebAssembly E-commerce Application Responsive with Flexbox

Cenk 1,021 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;
    }
} 
ASP.NET Core
ASP.NET Core
A set of technologies in the .NET Framework for building web applications and XML web services.
4,717 questions
Blazor
Blazor
A free and open-source web framework that enables developers to create web apps using C# and HTML being developed by Microsoft.
1,640 questions
0 comments No comments
{count} votes

1 answer

Sort by: Most helpful
  1. Bruce (SqlWork.com) 68,876 Reputation points
    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

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.