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:
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;
}
}