픽셀 정확한 WebView

게시일: 2014년 2월 28일

WebView에 적합한 인터페이스를 만드는 데 사용할 수 있는 여러 옵션이 있습니다.

표시 영역 메타 태그 설정

뷰포트 메타 태그는 웹 앱에 추가해야 하는 가장 중요한 태그입니다. 이 태그가 없으면 WebView가 사이트가 데스크톱 브라우저용으로 설계된 것처럼 작동할 수 있습니다. 이렇게 하면 웹페이지의 너비가 더 커지고 (일반적으로 980픽셀) WebView 너비에 맞게 크기가 조정됩니다. 대부분의 경우 페이지의 작은 개요 버전이 표시되며 사용자가 콘텐츠를 실제로 읽으려면 화면 이동 및 확대/축소를 해야 합니다.

사이트의 너비를 WebView 너비의 100% 로 설정하려면 표시 영역 메타 태그를 설정하세요.

<meta name="viewport" content="width=device-width, initial-scale=1">

width를 특수 값 device-width로 설정하여 페이지 레이아웃을 더 효과적으로 제어합니다.

기본적으로 WebView는 데스크톱 표시 영역으로 기본 설정되지 않고 표시 영역을 device-width로 설정합니다. 하지만 안정적이고 제어된 동작을 위해 뷰포트 메타 태그를 포함하는 것이 좋습니다.

데스크톱 사이트 표시

경우에 따라 휴대기기에 맞게 설계되지 않은 콘텐츠를 표시해야 할 수 있습니다. 예를 들어 관리하지 않는 콘텐츠를 표시할 수 있습니다. 이 경우 WebView가 데스크톱 크기의 표시 영역을 사용하도록 강제할 수 있습니다.

이러한 메서드가 설정되지 않고 표시 영역이 지정되지 않으면 WebView는 콘텐츠 크기를 기반으로 표시 영역 너비를 설정하려고 시도합니다.

또한 글꼴 크기를 늘려 휴대기기에서 더 읽기 쉽게 만드는 레이아웃 알고리즘 TEXT_AUTOSIZING를 사용하는 것이 좋습니다. setLayoutAlgorithm을 참고하세요.

반응형 디자인 사용

반응형 디자인은 화면 크기에 따라 변경되는 인터페이스를 설계하는 접근 방식입니다.

반응형 디자인을 구현하는 방법에는 여러 가지가 있습니다. 가장 일반적인 방법 중 하나는 기기의 특성을 기반으로 요소에 CSS를 적용하는 @media 쿼리입니다.

예를 들어 방향을 기반으로 세로 레이아웃에서 가로 레이아웃으로 전환하려고 한다고 가정해 보겠습니다. CSS 속성을 기본적으로 세로 모드로 설정합니다.

.page-container {
    display: -webkit-box;
    display: flex;

    -webkit-box-orient: vertical;
    flex-direction: column;

    padding: 20px;
    box-sizing: border-box;
}

가로 레이아웃으로 전환하려면 방향에 따라 flex-direction 속성을 전환합니다.

@media screen and (orientation: landscape) {
  .page-container.notification-opened {
    -webkit-box-orient: horizontal;
    flex-direction: row;
  }

  .page-container.notification-opened > .notification-arrow {
    margin-right: 20px;
  }
}

화면 너비에 따라 레이아웃을 변경할 수도 있습니다.

예를 들어 실제 화면 크기가 커질수록 버튼 너비의 크기를 100% 에서 더 작은 크기로 조정합니다.

button {
  display: block;
  width: 100%;
  ...
}

@media screen and (min-width: 500px) {
  button {
    width: 60%;
  }
}

@media screen and (min-width: 750px) {
  button {
    width: 40%;
    max-width: 400px;
  }
}

이는 사소한 변경사항이지만 UI에 따라 미디어 쿼리를 사용하면 동일한 HTML을 유지하면서 애플리케이션의 모양을 훨씬 더 크게 변경할 수 있습니다.

선명한 이미지

다양한 화면 크기와 밀도는 이미지에도 문제를 야기합니다. 이미지가 작을수록 메모리가 적게 필요하고 로드 속도가 더 빠르지만 크기를 조정하면 흐리게 보입니다.

다음은 모든 화면에서 이미지가 선명하게 표시되도록 하는 몇 가지 도움말 및 팁입니다.

  • 확장 가능한 효과에는 CSS를 사용하세요.
  • 벡터 그래픽을 사용합니다.
  • 고해상도 사진을 제공합니다.

확장 가능한 효과에 CSS 사용

가능하면 이미지 대신 CSS를 사용하세요. 일부 CSS 속성 조합은 렌더링하는 데 비용이 많이 들 수 있습니다. 항상 사용 중인 특정 조합을 테스트하세요.

사용자가 페이지로 처음 이동한 시점부터 페이지 콘텐츠의 일부가 화면에 렌더링되는 시점까지의 시간을 측정하는 콘텐츠가 포함된 첫 페인트 (FCP)에 대해 자세히 알아보세요. '콘텐츠'는 텍스트, 이미지 (배경 이미지 포함), <svg> 요소, 흰색이 아닌 <canvas> 요소를 의미합니다.

벡터 그래픽 사용

Scalable Vector Graphics (SVG)는 확장 가능한 이미지를 제공하는 좋은 방법입니다. 벡터 그래픽에 적합한 이미지의 경우 SVG는 매우 작은 파일 크기로 고품질 이미지를 제공합니다.

고해상도 사진 제공

고DPI 기기에 적합한 사진을 사용하고 CSS를 사용하여 이미지의 크기를 조정합니다. 이렇게 하면 이미지가 여러 기기에서 고화질로 렌더링될 수 있습니다. 이미지를 생성할 때 높은 압축 (낮은 품질 설정)을 사용하면 적절한 파일 크기로 우수한 시각적 결과를 얻을 수 있습니다.

이 접근 방식에는 몇 가지 단점이 있습니다. 압축이 심한 이미지에는 시각적 아티팩트가 표시될 수 있으므로 허용 가능한 압축 수준을 결정하기 위해 실험을 진행해야 합니다. 또한 CSS에서 이미지 크기를 조정하는 것은 비용이 많이 드는 작업일 수 있습니다.

높은 압축이 필요하지 않은 경우 상대적으로 작은 파일 크기로 고품질 이미지를 제공하는 WebP 형식을 사용해 보세요. WebP가 지원되지 않는 Android 버전에는 대체 항목을 제공해야 합니다.

세밀한 제어

대부분의 경우 모든 기기에 하나의 이미지를 사용할 수 없습니다. 이 경우 화면 크기와 밀도에 따라 다른 이미지를 선택할 수 있습니다. 미디어 쿼리를 사용하여 화면 크기 및 밀도별로 배경 이미지를 선택합니다.

JavaScript를 사용하여 이미지 로드 방식을 제어할 수 있지만 복잡성이 증가합니다.

미디어 쿼리 및 화면 밀도

화면 밀도를 기반으로 이미지를 선택하려면 미디어 쿼리에서 dpi 또는 dppx 단위를 사용해야 합니다. dpi 단위는 CSS 인치당 도트를 나타내고 dppx는 CSS 픽셀당 도트를 나타냅니다.

다음 표에서 dpidppx의 관계를 확인할 수 있습니다.

기기 픽셀 비율 일반화된 화면 밀도 CSS 인치당 도트 수 (dpi) CSS 픽셀당 점 (dppx)
1x MDPI 96dpi 1dppx
1.5배 HDPI 144dpi 1.5dppx
2 XHDPI 192dpi 2dppx

일반화된 화면 밀도 버킷은 Android에서 정의하며 화면 밀도를 표현하기 위해 다른 곳에서 사용됩니다 (예: https://screensiz.es).

배경 이미지

미디어 쿼리를 사용하여 요소에 배경 이미지를 할당할 수 있습니다. 예를 들어 픽셀 비율이 1.0인 기기에 256x256픽셀 크기의 로고 이미지가 있는 경우 다음 CSS 규칙을 사용할 수 있습니다.

.welcome-header > h1 {
  flex: 1;

  width: 100%;

  max-height: 256px;
  max-width: 256px;

  background-image: url('../images/html5_256x256.png');
  background-repeat: no-repeat;
  background-position: center;
  background-size: contain;
}

기기 픽셀 비율이 1.5(hdpi) 및 2.0 (xhdpi)인 기기에서 더 큰 이미지로 교체하려면 다음 규칙을 추가하면 됩니다.

@media screen and (min-resolution: 1.5dppx) {
  .welcome-header > h1{
    background-image: url('../images/html5_384x384.png');
  }
}

@media screen and (min-resolution: 2dppx) {
  .welcome-header > h1{
    background-image: url('../images/html5_512x512.png');
  }
}

그런 다음 이 기법을 min-width와 같은 다른 미디어 쿼리와 병합할 수 있습니다. 이는 다양한 폼 팩터를 고려할 때 유용합니다.

@media screen and (min-resolution: 2dppx) {
  .welcome-header > h1{
    background-image: url('../images/html5_512x512.png');
  }
}

@media screen and (min-resolution: 2dppx) and (min-width: 1000px) {
  .welcome-header > h1{
    background-image: url('../images/html5_1024x1024.png');

    max-height: 512px;
    max-width: 512px;
  }
}

max-heightmax-width가 1024x1024픽셀 이미지의 2ddpx 해상도에서 512픽셀로 설정된 것을 볼 수 있습니다. CSS '픽셀'은 실제로 기기 픽셀 비율 (512픽셀 * 2 = 1024픽셀)을 고려하기 때문입니다.

<img/>은(는) 어떠신가요?

현재 웹에는 이 문제를 해결할 수 있는 방법이 없습니다. 몇 가지 제안이 있지만 현재 브라우저나 WebView에서는 사용할 수 없습니다.

그동안 JavaScript에서 DOM을 생성하는 경우 다음과 같이 사려 깊은 디렉터리 구조로 여러 이미지 리소스를 만들 수 있습니다.

images/
  mdpi/
    imagename.png
  hdpi/
    imagename.png
  xhdpi/
    imagename.png

그런 다음 픽셀 비율을 사용하여 가장 적합한 이미지를 가져옵니다.

function getDensityDirectoryName() {
  if(!window.devicePixelRatio) {
    return 'mdpi';
  }

  if(window.devicePixelRatio > 1.5) {
    return 'xhdpi';
  } else if(window.devicePixelRatio > 1.0) {
    return 'hdpi';
  }

  return 'mdpi';
}

또는 페이지의 기본 URL을 변경하여 이미지의 상대 URL을 정의할 수 있습니다.

<!doctype html>
<html class="no-js">
<head>
  <script>
    function getDensityDirectoryName() {
      if(!window.devicePixelRatio) {
          return 'mdpi';
      }

      if(window.devicePixelRatio > 1.5) {
          return 'xhdpi';
      } else if(window.devicePixelRatio > 1.0) {
          return 'hdpi';
      }

      return 'mdpi';
    }

    var baseUrl =
        'file:///android_asset/www/img-js-diff/ratiores/'+getDensityDirectoryName()+'/';
    document.write('<base href="'+baseUrl+'">');
  </script>

    ...
</head>
<body>
    ...
</body>
</html>

이 접근 방식은 페이지 로드를 차단하고 기본 URL이 밀도별 디렉터리를 가리키므로 이미지, 스크립트, CSS 파일과 같은 모든 리소스에 절대 경로를 사용하도록 강제합니다.