Elm开发:页面加载及resize时获取窗口宽度以适配图片
Hey there! Let's break down your Elm landing page challenges into two solvable parts—grabbing the initial window width on page load, and swapping out images in a cleaner way than using background-image.
You already have resize handling set up, but to get the width on page load, you can use Browser.Dom.getViewport to fetch the initial viewport dimensions. Here's how to wire this into your Elm architecture:
First, update your Msg type to handle the initial viewport data:
type Msg = GotInitialViewport Browser.Dom.Viewport | WindowResized Int Int
Then, in your init function, send a command to fetch the viewport immediately:
import Browser.Dom import Task init : () -> ( Model, Cmd Msg ) init _ = ( { windowWidth = 0 -- Temporary placeholder; will be updated shortly , -- Your other model fields here } , Browser.Dom.getViewport |> Task.perform GotInitialViewport )
Next, handle the viewport response in your update function, and reuse the same logic for resize events to keep things DRY:
update : Msg -> Model -> ( Model, Cmd Msg ) update msg model = case msg of GotInitialViewport viewport -> ( { model | windowWidth = round viewport.viewport.width } , Cmd.none ) WindowResized width _ -> ( { model | windowWidth = width } , Cmd.none )
Your existing resize subscription stays mostly the same—just map to the new WindowResized msg:
import Window subscriptions : Model -> Sub Msg subscriptions _ = Window.resizes (\{ width, height } -> WindowResized width height)
This way, your model will have the correct window width right after the page loads, not just when the window is resized.
Using background-image for content images is far from ideal—they're not semantic, hard to make accessible, and miss out on native image features like lazy loading. Instead, use a standard <img> tag and dynamically set its src based on your window width state.
Here's how to implement this in your view:
view : Model -> Html Msg view model = let -- Define your breakpoints and image paths clearly mobileBreakpoint = 768 heroImageSrc = if model.windowWidth < mobileBreakpoint then "/images/hero-mobile.jpg" else "/images/hero-desktop.jpg" in div [ class "hero-container" ] [ img [ src heroImageSrc , alt "Hero banner: Your landing page headline here" -- Critical for accessibility , class "hero-image" , loading "lazy" -- Optional: Enable native lazy loading ] [] -- Add your other landing page content here ]
Why this is better than background-image:
- Semantics: Search engines and screen readers recognize
<img>as content, whereas background images are treated as decorative. - Accessibility: You can easily add descriptive
alttext, which is impossible with background images. - Control: Native image attributes like
loading="lazy"orwidth/heighthelp with performance and layout stability. - Maintainability: The image logic lives directly in your view, tied to your state, making it easier to debug and update than modifying CSS styles dynamically.
If you want to take it a step further, you can even handle image loading states (e.g., show a spinner while the image loads) by adding onLoad and onError handlers to the <img> tag and updating your model accordingly.
内容的提问来源于stack exchange,提问作者Mr Matten

