Intelligent Assistant
Chat with our virtual assistant to get answers promptly.
This topic describes how to adapt different Web components on multiple devices. It also introduces multi-device adaptation capabilities provided by the Web components, such as relative unit, media query, and window change listener, and provides adaptation solutions for the common layouts, such as grid, custom dialog box, and carousel layout.
During web development, attributes such as the element size and margin are used to adjust the page effect. When defining these attributes, you need to use the following element size units provided by CSS:
Unit | Relative Element | Application Scenarios | Sample Code |
|---|---|---|---|
% | A percentage unit, relative to the size of the parent element. | It is often used in responsive design to adjust the size of an element relative to its parent element. | .parent {
width: 400px;
}
.child {
width: 50%; /* 200px */
} |
em | Relative to the font size of the current element. If the font size of the current element is not set, it is relative to that of its parent element. | Used for font size and text-based spacing to change the layout. | p {
font-size: 16px;
}
span {
font-size: 1.5em; /* 24px */
} |
rem | Relative to the font size of the root element (HTML element). | Similar to em, but rem allows for more consistent layouts because all rem values are based on the size of the same root element and are easy to adjust globally. | html {
font-size: 16px;
}
p {
font-size: 1rem; /* 16px */
}
span {
font-size: 1.5rem; /* 24px */
} |
vw/vh | vw is relative to the browser window width, and vh is relative to the browser window height. | The element size is entirely based on the window width, for example, a pop-up mask layer. | .overlay {
width: 100vw; /* equal to the width of the viewport */
height: 100vh; /* equal to the height of the viewport */
} |
The px unit set on CSS is automatically converted based on the Device Pixel Ratio (DPR), so that the px unit has the same visual effect as the vp unit on HarmonyOS. This feature shields the physical pixel differences of devices and facilitates the migration of web apps to HarmonyOS.
Media query allows you to apply different style rules based on device features (such as screen size, resolution, and orientation). In this way, the web page can have a good display effect in different devices and screen sizes, thereby improving user experience. When the web page is adapted to multiple devices running HarmonyOS, the size ranges of horizontal and vertical breakpoints are the same as the recommended breakpoint ranges on HarmonyOS.
Use the width-height ratio for the vertical breakpoints on the web side and the height-width ratio on HarmonyOS.
For example, in the following code for media query, when the viewport width is greater than or equal to 840 px, the size of the font in article style changes to 20 px. When the viewport width is greater than or equal to 320 px and less than 600 px, and the aspect ratio is greater than or equal to 1/1.2 and less than or equal to 1/0.8, it matches the criteria for a small window in horizontal split-screen mode on smartphones, and the font size will be changed to 14 px.
@media (840px<=width) {
.article {
font-size: 20px;
}
}
@media (320px<=width<600px ) and (min-aspect-ratio: 1/1.2) and (max-aspect-ratio: 1/0.8){
.article {
font-size: 14px;
}
}Scenario 1: Changing the Font Size
Use the media query capability @media of CSS to set the font size in different breakpoints to implement responsive layout. The following uses sm, md, and lg as examples.
.title {
font-size: 14px;
}
@media (320px<=width<600px) {
.title {
font-size: 16px;
}
}
@media (600px<=width<840px) {
.title {
font-size: 18px;
}
}
@media (840px<=width) {
.title {
font-size: 20px;
}
}As such, the font size automatically adjusts according to the screen size.
Scenario 2: Changing the Image Width
Use the media query capability @media of CSS to set the image width in different breakpoints to implement responsive layout. The following uses sm, md, and lg as examples.
.cover {
width: 100px;
height: 100px;
}
@media (320px<=width<600px) {
.cover {
width: 120px;
height: 120px;
}
}
@media (600px<=width<840px) {
.cover {
width: 160px;
height: 160px;
}
}
@media (840px<=width) {
.cover {
width: 240px;
height: 240px;
}
}As such, the element size automatically adjusts according to the screen size.
The window object provides the resize event listener. This event is triggered when the document view (window) is resized. If the relative unit and media query cannot be used to implement a responsive layout across devices, you can register a resize event listener in JavaScript, and then obtain the window height through window.innerHeight and the window width through window.innerWidth. Based on the obtained window size, you can use CSS and HTML to implement responsive design. The following example demonstrates how to proportionally adjust the font size based on the window width.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Responsive Font Size on Resize</title>
<style>
html {
font-size: 16px;
}
.content {
padding: 20px;
}
.content h1,
.content p {
margin: 0 0 1em;
}
</style>
</head>
<body>
<div class="content">
<h1>Responsive Font Size Example</h1>
<p>Resize the window to see the font size change.</p>
</div>
</body>
</html>
<script>
const root = document.documentElement;
const initialScale = window.innerWidth / 1920;
root.style.fontSize = `${initialScale * 16}px`;
// Listen for window size change events
window.addEventListener('resize', () => {
const newScale = window.innerWidth / 1920;
root.style.fontSize = `${newScale * 16}px`;
});
</script>CSS provides the grid layout, which is similar to the responsive grid layout (GridRow/GridCol). It divides web page content into grids and combines different grids to make various layouts.

This section describes only some key concepts of the grid layout. For more details, refer to the CSS Grid documentation.
To use the grid layout, perform the following steps:
The following sample code demonstrates how to arrange grid items in two rows and three columns, with a column width and row height of 100 px and row and column spacing of 20 px.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Demo</title>
</head>
<style>
.container {
display: grid;
gap: 20px;
grid-template-columns: 100px 100px 100px;
grid-template-rows: 100px 100px;
}
.container .grid-item {
background-color: #f6fdf5;
text-align: center;
line-height: 100px;
}
</style>
<body>
<div class="container">
<div class="grid-item">1</div>
<div class="grid-item">2</div>
<div class="grid-item">3</div>
<div class="grid-item">4</div>
<div class="grid-item">5</div>
<div class="grid-item">6</div>
</div>
</body>
</html>
When there is a small quantity of elements, you can define the column widths by writing the values one by one (for example, grid-template-columns: 100px 100px 100px). However, if there are a large quantity of elements, for example, 10 columns in a row, you can use repeat() to improve the code readability. This function has two parameters. The first parameter is the number of repetitions and the second parameter is the value to be repeated, for example, grid-template-columns: repeat(3, 100px). When multiple columns should be defined, repeat() significantly improves the readability and conciseness of the code.
The grid layout can be used with media query to implement responsive layouts across devices. You can arrange the layout with different size ranges to achieve different effects on various screen sizes. The following table lists the grid layout effects.
Item | sm | md | lg |
|---|---|---|---|
Final effect |
|
|
|
@media (320px<=width<600px) {
.grid-functions {
grid-template-columns: repeat(4, 48px);
row-gap: 12px;
}
}@media (600px<=width<840px) {
.grid-functions {
grid-template-columns: repeat(6, 48px);
row-gap: 20px;
}
}@media (840px<=width) {
.grid-functions {
grid-template-columns: repeat(8, 48px);
row-gap: 24px;
}
}Larger dialog boxes are displayed on large-sized devices to prevent the content from being too small to see. Use the media query capability @media of CSS to set the dialog box size at different breakpoints. The following table lists the dialog box effects.
Item | sm | md | lg |
|---|---|---|---|
Final effect |
|
|
|
@media (320px<=width<600px) {
.custom-dialog {
width: 328px;
height: 344px;
}
}@media (600px<=width<800px) {
.custom-dialog {
width: 360px;
height: 378px;
}
}@media (800px<=width) {
.custom-dialog {
width: 393px;
height: 412px;
}
}Responsive design is required not only for the size of the dialog box, but also for its content. However, because the content of the dialog box is highly customized, it is difficult to provide a unified manner for adaptation. You need to tailor an appropriate adaptation solution based on the content.
The carousel layout provides the function of playing multiple images in turn. Although the native Web does not provide the component that directly implements the carousel layout, you can use some methods or reuse the third-party component library to implement the carousel layout. The key points of responsive carousel layout design are as follows:
The following table lists the carousel effects and uses React as an example.
Item | sm | md | lg |
|---|---|---|---|
Final effect |
|
|
|
const Banner = () => {
const banner = [
{ id: "001", url: "assets/banner01.png" },
{ id: "002", url: "assets/banner02.png" },
{ id: "003", url: "assets/banner03.png" },
{ id: "004", url: "assets/banner04.png" },
];
const [currentIndex, setCurrentIndex] = useState(1);
const [currentDot, setCurrentDot] = useState(0);
const [width, setWidth] = useState<number>(0);
const [singleOffset, setSingleOffset] = useState<number>(0);
const [initOffset, setInitOffset] = useState<number>(0);
const [gap, setGap] = useState(16);
const [animate, setAnimate] = useState("transform 0.5s ease");
const [dotVisible, setDotVisible] = useState(false);
const wrapperRef = useRef<HTMLDivElement>(null);
const totalItems = banner.length;
useEffect(() => {
const updateLayout = () => {
const winWidth = window.innerWidth;
if (winWidth < 600) {
setGap(0); // set the distance between elements under the sm breakpoint.
setWidth(winWidth - 32); // set the element width under the sm breakpoint.
setSingleOffset(winWidth - 32); // set the single displacement under the sm breakpoint.
setInitOffset(0); // set the initial offset under the sm breakpoint.
setDotVisible(true);
} else if (winWidth < 840) {
setGap(12); // set the distance between elements under the md breakpoint.
setWidth((winWidth - 48 - gap) / 2); // set the element width under the md breakpoint.
setSingleOffset(width + gap); // set the single displacement under the md breakpoint.
setInitOffset(24); // set the initial offset under the md breakpoint.
setDotVisible(false);
} else {
setGap(16); // set the distance between elements under the lg breakpoint.
setWidth((winWidth - 250 - gap) / 2); // set the element width under the lg breakpoint.
setSingleOffset(width + gap); // set the single displacement under the lg breakpoint.
setInitOffset(125); // set the initial offset under the lg breakpoint.
setDotVisible(false);
}
};
updateLayout();
window.addEventListener("resize", updateLayout);
return () => window.removeEventListener("resize", updateLayout);
}, [gap, width]);
useEffect(() => {
const interval = setInterval(() => {
setCurrentIndex((prev) => prev + 1);
setCurrentDot((p) => (p + 1) % banner.length);
}, 3000);
return () => clearInterval(interval);
});
useEffect(() => {
if (currentIndex === totalItems + 1) {
setTimeout(() => {
setAnimate("none");
setCurrentIndex(1);
setTimeout(() => {
setAnimate("transform 0.5s ease");
}, 50);
}, 550);
}
}, [currentIndex, totalItems]);
return (
<div className="banner-container">
<div
className="banner-wrapper"
ref={wrapperRef}
style={{
transform: `translateX(-${
currentIndex * singleOffset - initOffset
}px)`,
transition: animate,
gap: `${gap}px`,
}}
>
{[banner[banner.length - 1], ...banner, ...banner].map(
(item, index) => (
<div
style={{
width,
}}
key={`${item.id}-${index}`}
className="banner-item"
>
<img src={item.url} alt={`banner-${item.id}`} />
</div>
)
)}
</div>
{dotVisible ? (
<div className="swiper-dot">
{banner.map((item, index) => (
<div
key={item.id}
className={`dot${currentDot === index ? " dot-active" : ""}`}
></div>
))}
</div>
) : (
<></>
)}
</div>
);
};
export default Banner;