Mastering Mobile Weather UI: REM Layout, Flexbox, Canvas & Performance Hacks

This article walks through the development of the HandQ Weather H5 page, covering REM‑based responsive layout, Flexbox sectioning, HTML5 canvas charts and animations, CSS3 transitions, and a suite of performance and compatibility optimizations for mobile browsers.

Tencent IMWeb Frontend Team
Tencent IMWeb Frontend Team
Tencent IMWeb Frontend Team
Mastering Mobile Weather UI: REM Layout, Flexbox, Canvas & Performance Hacks

Introduction

HandQ Weather is a feature added in QQ version 6.0 and above. The page displays the current temperature, a five‑day temperature line chart, a 24‑hour temperature chart, and eight different weather animations such as rain, snow, clouds, and sunlight.

1. REM Overall Layout

For mobile devices, resolution adaptation is a common problem. Designers usually provide a visual draft based on iPhone 6 (750 px). Using REM for the whole layout is an excellent solution.

What is REM?

rem (root element font size) is a relative unit that depends on the font size of the root element.

Basic Syntax

/* Define html root element font size */
html {
    font-size: 10px;
}
/* Use rem for child elements */
.sonDom {
    width: 6rem;   /* 6 × 10 = 60 px */
    height: 3rem;  /* 3 × 10 = 30 px */
    line-height: 3rem;
    font-size: 1.2rem; /* 1.2 × 10 = 12 px */
    border-radius: .5rem; /* 0.5 × 10 = 5 px */
}

Because 1 rem equals the root element’s font‑size value , changing the root font-size proportionally changes all elements that use rem, achieving perfect resolution adaptation.

How to Change the Root Font‑Size Dynamically

Two common methods are used:

1. Media Queries

/* Default 20px */
html {font-size: 20px;}
@media only screen and (min-width: 320px) {html {font-size: 10px;}}
@media only screen and (min-width: 375px) {html {font-size: 16px;}}
@media only screen and (min-width: 414px) {html {font-size: 20px;}}

2. JavaScript

// Set font size dynamically
var doc = document,
    win = window;
function initFontSize() {
    var docEl = doc.documentElement,
        resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',
        recalc = function () {
            var clientWidth = docEl.clientWidth;
            if (!clientWidth) return;
            var fontSizeRate = clientWidth / 375,
                baseFontSize = 15 * fontSizeRate;
            docEl.style.fontSize = baseFontSize + 'px';
        };
    recalc();
    if (!doc.addEventListener) return;
    win.addEventListener(resizeEvt, recalc, false);
    doc.addEventListener('DOMContentLoaded', recalc, false);
}

2. Flexbox Local Layout

Previously, equal‑width layouts were achieved with floats or inline‑block, both requiring clearfixes or margin tweaks. CSS3 Flexbox offers a cleaner solution.

Compatibility

Modern Android and iOS browsers support Flexbox well, making it a safe choice for mobile development.

HandQ Weather Example

The page is divided into five equal parts, each occupying the same width.

HTML Structure

Flexbox CSS

/* Set container as flexbox */
.info-day-list {
    display: -webkit-box;
    padding: 1rem 0;
}
/* Set each item */
.info-day-item {
    -webkit-box-flex: 1;  /* equal proportion */
    width: 1%;
    font-size: 1.4rem;
    line-height: 3rem;
    text-align: center;
}

All items have box-flex: 1, so they share the remaining space equally.

Flexbox Pitfalls

1. Uneven Width Due to Text Length

When the weather description length varies (e.g., "southwest wind" vs. "light breeze"), the items may not divide evenly. Setting a uniform width: 1% on the child elements resolves the issue.

3. HTML5 Canvas

Complex animations such as temperature line charts, rain, and snow are more performant when drawn on a canvas instead of manipulating the DOM.

Line Chart

Rain & Snow Animation

Canvas Pitfalls

1. High‑DPI Blur

On retina screens, the canvas appears blurry because the device pixel ratio (DPR) is greater than 1. The solution is to scale the canvas size according to devicePixelRatio:

// Adjust canvas for high‑DPI screens
var c = document.getElementById("canvas");
var DPR = window.devicePixelRatio;
// Assume canvasWidth and canvasHeight are the CSS dimensions
c.width = canvasWidth * DPR;
c.height = canvasHeight * DPR;

2. Memory Consumption

Canvas can consume a lot of memory, especially when many particles (rain drops, snowflakes) are rendered. Avoid creating multiple canvases and limit the number of particles on low‑end devices.

4. CSS3 Transition & Animation

Transitions and keyframe animations are used for interactive effects such as the zodiac slider.

Slider Example

.star-icon-outside-l {
    z-index: 20;
    -webkit-transform: translateX(-18.8rem) scale(.673);
    transform: translateX(-18.8rem) scale(.673);
}
/* ... other icon classes omitted for brevity ... */

Keyframe Examples

@-webkit-keyframes toggleShow {
    0%   {opacity: 0;}
    11%  {opacity: 0;}
    12.5%{opacity: 1;}
    20%  {opacity: 0;}
    100% {opacity: 0;}
}

@-webkit-keyframes shine {
    0%   {-webkit-transform: scale(1,1);}
    50%  {-webkit-transform: scale(1.2,1.2);}
    100% {-webkit-transform: scale(1,1);}
}

5. Performance Optimizations

Basic Animation Optimization

Prefer transform: translate() over left/right and use 3D acceleration where possible.

Use requestAnimationFrame

// Polyfill for requestAnimationFrame
window.requestAnimFrame =
    window.requestAnimationFrame ||
    window.webkitRequestAnimationFrame ||
    function(callback) { return window.setTimeout(callback, 1000 / 30); };

Canvas Optimization

Reduce particle count on low‑end phones by decreasing OPTS.maxNum when frame time exceeds a threshold.

// Reduce max number of drops if frame takes too long
if (new Date - lastTime > 30 && drops.length < OPTS.maxNum && OPTS.maxNum > 21) {
    OPTS.maxNum -= 10;
}

Memory Optimization

Pause the weather webview when it is hidden to save memory:

if (mqq && mqq.iOS && mqq.addEventListener) {
    mqq.addEventListener("qbrowserVisibilityChange", function(e) {
        cancelAnimationFrame(drp_ticker);
        if (!e.hidden) { update(); }
    });
}

Caching

Store weather data in localStorage and reuse it on subsequent loads.

if (checkCache('weather-local_weather_info')) {
    Page.processData(local_weather_info);
    weather_info = local_weather_info;
} else {
    Vinda.getData('data-weatherInfo', function(data) {
        if (data && data.retcode == 0) {
            Page.processData(data);
            $.extend(data.result, {searchTime: +Date.now(), city: city});
            $S.save({key: 'local_weather_info', value: data});
        }
    });
}

Pre‑loading

DNS pre‑fetch: <link rel="dns-prefetch" href="//pub.idqqimg.com" /> CGI pre‑loading to fetch data before JS execution.

Code Optimizations

Reuse DOM objects for the zodiac slider (7 DOM nodes for 12 items) and load low‑weight modules asynchronously.

// Module definition
var Page = {};
var headerMod = {};
var timeDegreeMod = {};
var adsMod = {};
var detailMod = {};
var AnimationMod = {};

Page.render = function() {
    headerMod.render();
    timeDegreeMod.render();
    detailMod.render();
    adsMod.getAds();
    require.async('./setAnimation', function(AMod) {
        AnimationMod = AMod;
        AnimationMod.init();
    });
};

Other Optimizations

Sprite sheets, file merging, resource compression, inline CSS/JS placed at the end to avoid render‑blocking.

6. Compatibility Issues

iOS App‑Ad Handling

When an ad is an iOS app download, a JSONP request retrieves the App Store link and launches the app via mqq.app.launchApp. Otherwise, a new webview is opened.

// Detect iOS app ad and launch
var isIosAppAds = mqq.iOS && mqq.device.isMobileQQ() && producttype == 19;
if (isIosAppAds) {
    $.ajax({url: adsMod.jump_url, data: {acttype: 1}, dataType: 'jsonp', success: function(o) {
        if (o && o.ret >= 0 && o.data && o.data.dstlink) {
            mqq.app.launchApp({name: o.data.dstlink});
        }
    }});
} else {
    mqq.ui.openUrl({url: adsMod.jump_url, target: 1, style: 0});
}

X5 Kernel Compatibility

In X5 tbs.1x, pseudo‑elements cannot be animated and transition‑timing‑function: ease‑out is unsupported. Support improves in tbs.2x.

Non‑ Tag Jump Bug

On low‑end Android devices, click handlers on div elements may trigger the reporting request but not the navigation. Using an a tag resolves the issue.

7. Shortcomings

High memory consumption due to numerous animations and canvas usage, especially on low‑memory phones.

Animation rendering and code still need refinement; the author acknowledges many areas for improvement.

Conclusion

QQ Weather H5 was the author’s first independent project at Tencent. Although the project has been handed over, revisiting the code and its evolution continues to provide valuable learning experiences.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Performance OptimizationCanvasResponsive DesignFlexboxrem
Tencent IMWeb Frontend Team
Written by

Tencent IMWeb Frontend Team

IMWeb Frontend Community gathering frontend development enthusiasts. Follow us for refined live courses by top experts, cutting‑edge technical posts, and to sharpen your frontend skills.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.