스트리밍은 대부분의 브라우저와
Developer 앱에서 사용할 수 있습니다.
-
Safari 및 WebKit의 새로운 기능
Safari 및 WebKit의 최신 기능을 살펴보고 더 우수하고 강력한 웹 사이트를 만드는 방법을 알아보세요. HTML의 최신 업데이트, CSS 개선 사항, Web Inspector 툴링, 웹 API 등을 살펴보겠습니다.
리소스
- Learn more about bug reporting
- MDN Web Docs - Web Extensions API
- Safari Release Notes
- Safari Technology Preview
- WebKit Open Source Project
관련 비디오
WWDC23
WWDC22
-
다운로드
♪ 부드러운 힙합 반주 ♪ ♪ 안녕하세요 전 Kendall Bagley이며 Safari 팀의 소프트웨어 엔지니어입니다 우리가 WWDC에서 함께한 지 1년이 지났습니다 오늘은 Safari와 WebKit의 놀라운 특징과 개선점에 대해 모두 이야기해 볼 건데 올해 WWDC에서 새롭게 다룰 내용과 작년 한 해 동안 봐왔던 내용을 다룰 겁니다 사실 정말 바쁜 한해였어요 작년 가을부터 Safari는 릴리즈 때마다 새롭고 흥미로운 기능을 선보였고 웹 개발자인 여러분이 요구한 사항들이었지요 올해 전달된 새로운 각 개선사항을 통해 여러분이 우리와 공유했던 피드백의 가장 큰 요점들을 다루려고 했습니다 :has() 의사 클래스와 상위 선택자 새로운 플렉스 박스 검사자 컨테이너 쿼리 추가처럼요 우리는 여러분의 일상 업무를 더 쉽고 편하게 만들면서 웹에서 가장 강력하고 최고인 소프트웨어를 구축하고 싶습니다 사실 오늘 살펴볼 새로운 내용들이 여기 있습니다 하지만 이 세션 하나에서 전부 다룰 수 없는 내용이 훨씬 많이 있죠 작년 7번의 Safari 릴리즈에서 총 162개의 새로운 웹 플랫폼 특성을 구현했고 개선을 이뤘습니다 여러분이 웹사이트와 웹 앱을 만들 때 사용할 수 있는 정말 많은 새 툴을 제공해서 정말 뿌듯했습니다 macOS의 경우 새롭고 신나는 걸 볼 최선의 방법은 Safari Technology Preview를 다 훑어본 다음 가능한데 Safari와 WebKit의 가장 근사한 최신 기능을 시험해 보고 나서 다음엔 뭘 다뤄야 할지 저희에게 알려주세요 여러분이 보셨듯이 새로운 기능이 대단히 많습니다 그러니 다룰 내용을 함께 샅샅이 살펴봅시다 오늘 새 HTML 특성들과 CSS 개선사항을 함께 살펴볼 겁니다 여기에 포함된 내용은 코드 아키텍처를 돕는 방법 새로운 Web Inspector 도구 새로운 API의 넓은 선택 범위 훌륭한 JavaScript와 WebAssembly 특성 보안과 프라이버시 개선사항입니다 그러니 제가 만들고 있는 동료들과 제가 사용할 웹페이지를 둘러보면서 HTML에 어떤 새로운 점이 있는지 살펴보도록 할게요 옷값을 절약하고 용도를 바꿔서 옷을 더 이용하고 싶은데 의류 교환 웹사이트가 제 팀도 시도해볼 수 있는 훌륭한 방법이라고 생각했습니다 제 사이트 디자인에는 Request Item 버튼이 있어 마음에 드는 옷을 발견할 때 채워야 하는 양식을 보여줘야 합니다 그리고 전체 페이지보다 높은 곳에 오버레이에서 보이는 양식을 원해요 새 대화 요소는 우리 요청 양식에 쓸 수 있는 튼튼하고 접근할 수 있는 방식으로 오버레이를 만드는 정말 쉬운 방식을 제공합니다 CSS의 새로운 배경 의사 엘리먼트는 모달 뒤의 배경을 디자인할 수 있게 해줍니다 물품을 요청해 대화를 띄워봅시다 저 그림자와 애니메이션 보이세요? 정말 괜찮죠? 그리고 우리 사이트에서 물품을 요청하면 그 물품의 게시자가 요청을 수락할 수 있어야 합니다 페이지의 제일 하단에 수신한 모든 요청을 훑어볼 수 있는 캐러셀이 있습니다 하지만 전 누가 클릭하거나 키보드를 이동해 제일 앞에 있지 않은 품목 하나를 버튼이나 텍스트 필드로 실수로 건드리길 바라지 않아요 이 부분을 수정하려고 비활성 속성을 사용할 수 있습니다 여기서 JavaScript로 비활성 속성을 동적으로 적용하여 엘리먼트 사이에서 전환하며 현재 선택되지 않은 슬라이드의 엘리먼트들의 상호작용을 불가능하게 하고 있습니다 비활성 속성 사용에는 보조 기술과 상호작용 불능 망가진 항목을 크게 읽는 스크린 읽기 방지가 포함되는데 어떤 엘리먼트가 상호작용하고 싶어 하는지 더 분명하게 안내합니다 마지막으로 HTML에 새로운 이미지 레이지 로딩 기능이 있어요 제 사이트의 헤더에 아이콘들이 있는데 당장 로드해야 하지만 의류 아이템 이미지들은 첫 번째 로드의 오프스크린에서 레이지 로딩을 사용할 수 있어 사용자가 스크롤 할 때만 이미지가 로드돼 페이지가 더 빠르고 즉각 반응하는 것처럼 느껴집니다 지금까지의 사이트가 정말 마음에 드는데 보조 기술을 사용하면 근사한 모습이 될 거예요 저 HTML 특성들은 시작한 지 얼마 안 됐습니다 올해는 CSS와 확인해볼 게 많기 때문입니다 우리 CSS에서 중점을 두는 큰 부분은 더 강력한 아키텍처로 CSS를 재사용하기 쉽게 만드는 것이었습니다 그와 함께 새로운 웹 기술의 1위 요청은 컨테이너 쿼리였습니다 컨테이너 쿼리가 Safari 16에 탑재된다는 사실을 알려드리게 되어 정말 신나요 여러분은 사이즈 쿼리와 컨테이너 쿼리 유닛 모두를 사용할 수 있게 됩니다 여기서 의류 교환 웹사이트의 대안 레이아웃을 실험하고 있습니다 의류 한 점을 재사용할 수 있는 컴포넌트로 보여주고 그 컴포넌트를 페이지 레이아웃의 여러 곳에 떨어뜨리는 카드를 만들고 있습니다 여기 사이드바엔 이용 가능한 공간이 좀 좁아서 컴포넌트 안의 모든 내용을 수직으로 쌓고 싶습니다 품목의 메인 그리드에서 첫 번째 이미지가 히어로 그래픽의 특징을 보이는데 히어로 그래픽은 가능한 수평 공간을 모두 차지하고 넓은 레이아웃에 더 어울리도록 패션 콘텐츠를 정렬합니다 주요 콘텐츠 영역의 나머지 품목은 더 작은 열로 나뉘어야 합니다 그래서 다른 레이아웃을 만들었는데 수평 공간에 중간 양이 있을 때 동작합니다 레이아웃에 변화를 주려고 미디어 쿼리가 아닌 컨테이너 쿼리를 사용하면 이 컴포넌트에 한 번만 레이아웃 코드를 쓸 수 있고 어떤 사이즈의 컨테이너에서도 사이트 어디서든 그 컴포넌트를 쓸 수 있어서 정확한 레이아웃이 항상 적용됩니다 전 어떤 엘리먼트를 컨테이너에 사용하는지 명시했고 인라인 사이즈만 측정하든 인라인과 블록 사이즈를 동시에 측정하든 컨테이너 타입 속성을 사용합니다 컨테이너 네임 속성을 사용해 컨테이너에 선택적으로 이름을 붙일 수 있는데 HTML을 구조화하는 방식에 따라 더 큰 유연성을 부여합니다 그리고 컨테이너 사이즈에 기반해 조건부로 스타일을 적용하려고 @container rule을 사용합니다 여기서 만약 컨테이너 안의 의류 카드 컴포넌트가 250픽셀보다 넓다면 그리드는 하나의 열 대신 둘을 갖도록 바뀔 것입니다 다음은 CSS 아키텍처인 Cascade 레이어입니다 이는 CSS Cascade에 강력한 변화입니다 CSS의 시작 이래로 Cascade는 다양한 레이어를 구성해 왔습니다 하지만 각 레이어 저자 스타일 안의 어떤 선택자가 어떻게 특별하던 웹 개발자로서 여러분이 쓰는 스타일은 늘 UA 스타일을 앞섭니다 인라인 스타일은 늘 저자 스타일보다 강력하고 계층의 나머지와 함께일 때 그렇습니다 Cascade 레이어는 같은 개념을 취하고 각 레이어 안에서 특별히 독립적으로 계산되는 커스텀 레이어를 생성하도록 허용합니다 하나의 전체 레이어는 사용되는 선택자가 얼마나 특별하든 다른 전체 레이어를 앞섭니다 그리고 여러분은 CSS에서 레이어를 규정하는 순서로 어떤 레이어가 다른 레이어보다 강력한지 결정합니다 Cascade 레이어는 큰 프로젝트에서 CSS를 설계하고 시간이 지나며 코드를 유지하는데 유용한 툴이 될 겁니다 여러분 팀은 Cascade 레이어를 프로젝트나 커스텀 스타일에 쓰는 프레임워크나 오버라이드에서 디자인 시스템을 분리하는 데 사용할지도 모릅니다 전적으로 여러분에게 달렸습니다 여러분의 CSS 아키텍처를 위해 놀랍고 새로운 향상 특성을 자세히 설명하는 건 :has()인데 오래 기다렸던 부모 선택자나 그 이상의 역할을 하는 의사 클래스입니다 CSS의 어떤 선택자와도 조합해서 :has()는 형제자매, 속성 폼 필드의 상태 말고도 많은 것을 찾아볼 수 있습니다 정말 강력합니다 여기서 전체 메시지 박스를 강조 표시하고 싶습니다 누가 자기 메시지 체크박스에 '긴급한가요?'에 체크할 때마다요 여기서 :has 의사 클래스를 폼 엘리먼트가 이 CSS에 적용하는 체크박스 유형과 체크된 체크박스에 인풋을 가질 때 사용할 수 있습니다 그리고 전 어떤 JavaScript도 사용할 필요가 없습니다 :has(), Cascade 레이어 컨테이너 쿼리로 여러분의 CSS 아키텍처를 다루는 모든 위대한 개선사항 덕에 웹 개발자인 여러분의 일이 훨씬 수월해지길 바랍니다 하지만 우리가 열광하는 CSS 추가사항은 여기서 끝이 아닙니다 여러분은 기존 뷰포트 유닛과 비슷한 툴을 원했지만 뷰포트의 사이즈를 바꾸는 스크롤링에서 기기에 더 유용할 겁니다 그걸 위해 모두를 위한 새로운 뷰포트 유닛이 있습니다 뷰포트의 높이를 알고 싶을 때 최소 높이라면 svh를 사용하세요 뷰포트의 높이가 최대 높이라면 lvh를 사용하세요 이것만 기억하세요 작은 건 s, 큰 건 l입니다 뷰포트의 현재 실제 높이에 맞게 바꾸는 동적 숫자의 경우는 dvh를 사용하세요 단지 높이를 위해서만은 아닙니다 우리는 더 많은 뷰포트 유닛도 다뤘습니다 높이 유닛과 맞추려고 자주 사용되는 완전성에 좋은 폭 유닛이 있습니다 블록과 인라인이 있는데 흐를 수 있는 텍스트의 다양한 방식과 다양한 언어에 쓸 때 유용합니다 그리고 최솟값과 최댓값도 잊지 않았습니다 하지만 페이지에서 그냥 반응하는 게 아니라 움직임을 살짝 만들어내고 싶다면 어떨까요? 애니메이션은 예전에 굉장히 서술적이었습니다 객체가 움직이게 하려고 시작, 끝, 기간을 명시할 수 있도록요 엘리먼트가 곡선을 따라가게 하려고 할 때나 오프셋 주변을 돌게 하려고 할 때 페이지에서 엘리먼트를 움직이는 건 어려웠습니다 클릭할 때 헤더에 비밀 애니메이션을 추가하고 싶은데 정말 재미있겠다고 생각했어요 새로운 오프셋 패스로 객체가 따라 움직이길 원하는 경로를 정의할 수 있습니다 오프셋 패스로 경로를 설정하고 키 프레임 효과를 위해 오프셋 디스턴스를 사용하세요 그러고 나서 키 프레임 효과를 적용하려 애니메이션 속성을 쓰면 모든 CSS에서 애니메이션으로 하고 싶은 모든 컨트롤을 줍니다 우리는 또 여러분의 페이지에 컨트롤을 더 주고 싶어요 브라우저 엔진 자체가 규정한 일반적인 웹의 일부분이나 첫 예시처럼 스크롤 행동을 넘어선 페이지를요 웹의 시작부터 링크를 클릭하면 웹페이지의 다른 부분으로 이동해 점프하는 것처럼 보입니다 가끔 이런 현상이 사용자들을 혼란스럽게 할 수 있습니다 CSS의 스크롤 행동 속성은 이런 현상을 원하는지 아닌지 명시할 수 있는 방법을 제공합니다 기본값은 오토로 설정되고 저렇게 점프하는 것처럼 보입니다 스크롤 행동을 '매끈하게'로 명시하면 브라우저가 페이지 다음 부분으로 부드럽게 스크롤 되도록 요청할 수 있습니다 JavaScript 방법으로는 window.scroll() scrollTo() 또는 scrollBy()로 이렇게 할 수 있습니다 여러분의 고객들이 최고라는 걸 알고 브라우저 엔진 디폴트 밖에서 웹페이지 경험을 규정할 수 있어야 하는데 이는 또한 :focus-visible과 accent-color가 작동하기 시작할 때 가능합니다 아마 포커스 선택자가 친숙할지 모르겠네요 전체적인 디자인이 더 일직선인 것처럼 포커스 선택자에 특정 스타일을 적용하고 싶었던 적이 있었을지 모릅니다 하지만 그렇게 할 때 브라우저 기반 체험을 잃을 접근성 위험이 있습니다 제 사이트에서는 내장된 형식 색상 대신에 커스텀 색상을 사용하고 싶어요 이미 제 헤더에 있던 청록색을 포커스 하이라이트와 체크박스 둘 다에 사용해 봅시다 :focus-visible 의사 클래스로 선택하는 대로 포커스 지시자의 스타일을 만들 수 있지만 브라우저에 의해 자연스럽게 보인다면 스타일을 구현한 지시자만 보이게 합니다 그리고 여러분의 폼에 또 다른 커스텀 레이어를 추가하려고 폼 컨트롤 UI의 여러 부분 색을 바꾸기 위해서 accent-color를 쓸 수 있습니다 저 체크박스뿐만 아니라 라디오 버튼, 훨씬 더 많은 것들에 영향을 줄 겁니다 또한 CSS로 WebKit 프리픽스를 더 많이 대체해 왔습니다 이것들은 실험적인 특성을 시도하기에 완벽한 방법으로 사용되었지만 지금은 쓰고 상호작용하기 더 쉽게 CSS를 만들려고 표준 규정 속성으로 나아갈 수 있습니다 하지만 걱정하지 마세요 기존 CSS와 WebKit 프리픽스는 웹 표준 규범 상대에게 이행되며 계속 같이 동작할 겁니다 Backface-visibility print-color-adjust text-align: match-parent는 모두 프리픽스 상대와 정확히 똑같습니다 text-combine-upright와 마스크 둘 다 표준 규격과 맞추기 위해 프리픽스 버전에서 구문을 업데이트했습니다 프리픽스 아닌 어피어런스 속성은 또한 새로운 자동값을 위해 지원을 추가하지만 Safari 16에선 표준 사양이 된 탈자 기호나 리스트 항목처럼 WebKit 특정 값을 삭제했습니다 추가된 서체에 대해서도 알아야 할 게 정말 많았어요 특히, 폰트 팔레트 속성을 추가해 컬러 폰트 내에서 컬러 팔레트를 쉽게 선택하도록 했습니다 제 사이트에서 가능성 있는 로고를 시도해본다면 정말 근사할 것 같아요 내장된 어두운색 혹은 밝은 팔레트로 어떻게 보이는지 테스트할 수 있고 혹은 색상을 정확히 오버라이드 하도록 커스텀하고 싶고 밝게 하려고 약간의 노란색을 주고 싶어요 서체와 관련해서 text-decoration-skip-ink가 추가되었는데 글자나 부호가 밑줄이나 작은 제목에 교차하면 생겨날 일을 제어하도록 해줍니다 게다가 ic 유닛은 블록 방향에 CJK 캐릭터가 정확히 줄을 서게 해줍니다 그건 중국어, 일본어 한국어와 같은 언어에서 깨끗한 서체 그리드를 만드는 데 유용합니다 이 모든 대단한 CSS 특징의 논의를 마무리하려면 서브그리드에 대한 이야기를 꼭 해야 합니다 수년간 웹의 레이아웃은 꽤 힘들었습니다 CSS 그리드는 혁신적이었지만 그리드 컨테이너의 직계 자식에게만 영향을 줍니다 여기서 이 카드들을 펼치고 미디어 쿼리 없이 열을 추가하고 삭제해 뷰포트 너비에 맞게 자동으로 레이아웃을 조정하기 위해 CSS 그리드를 사용하고 있습니다 하지만 각 카드의 콘텐츠 사이즈는 같지 않습니다 일부 헤드라인은 더 길고 사진들의 가로세로비가 달라서 꽤 지저분해 보입니다 모든 Request Item 버튼과 메시지 박스를 페이지 전체에서 일렬로 놓고 싶고 한 카드의 더 긴 타이틀로 다른 카드에 영향을 주어 모든 카드 간격을 똑같게 만들고 싶어요 이제 서브그리드를 사용해 해낼 수 있습니다 각 아티클에 그리드를 넣었고 단순하게 'grid-template-rows: subgrid'라고 쓰면서 모든 그리드를 부모 그리드에 묶으려고 했습니다 이제 각 의류 카드에서 모든 콘텐츠를 볼 수 있는데 필요할 때도 모든 그리드를 켜서 Web Inspector에서 Grid Inspector를 사용해 완벽하게 줄을 세웁니다 Web Inspector를 사용하면 많은 CSS 작업이 쉬워집니다 사실 Web Inspector에 대단한 추가사항이 많아서 정말 시도해보고 싶으실 거예요 우선 어떤 상황인지 볼 수 있을 때 레이아웃을 쓰기 쉬운데 그건 Web Inspector를 굉장히 중요하게 만듭니다 그리고 새로운 Flexbox Inspector로 엘리먼트 사이의 공간을 실제로 시각화할 수 있습니다 여기 제 웹사이트에서 헤더에 이 아이콘들을 추가하는 데 어려움이 좀 있었습니다 제가 해야 할 일은 엘리먼트를 검사하고 Layout 탭으로 가는 건데 지금은 제 그리드가 우려스럽지 않으니 새로운 Flexbox Inspector를 다루기 위해 곧바로 그 부분으로 갈 수 있습니다 그저 클릭 한 번으로 모든 view를 켤 수 있는데 여전히 성능이 좋습니다 그리고 모든 view를 켜서 해쉬 마크와 컨테이너 박스로 제 엘리먼트가 어떻게 배열되어 있고 view가 차지한 빈 곳이 어떤지 명확히 볼 수 있습니다 그래서 이젠 새 정렬 편집기에 쓸 수 있도록 바르게 정렬하고 싶습니다 Styles 탭에 가서 align-item 옆에 있는 새로운 버튼을 찾을 수 있습니다 여기서 제 헤더에 뭐가 가장 적합한지 다양한 옵션을 훑어볼 수 있고 justify-content로도 똑같이 할 수 있습니다 다시 각 옵션을 훑어본 다음에 정확하다고 생각하는 거로 정착합니다 또한 노란색 아이콘이 너무 작다고 생각해서 빨간색 아이콘과 같은 크기로 만들고 싶어요 이름에 'medium'이 들어간 변수를 사용하고 있다고 믿는데 정말로 완전한 이름을 기억할 수 없어요 점검 도구에서 높이를 편집하고 노란 아이콘 하나를 검사해 사이즈 바꾸기를 시도할 수 있습니다 우리의 새로운 CSS 퍼지 자동 완성 덕택에 'medium'이 이름 끝에 있어도 즉시 'medium' 유형으로 가서 튀어나오길 바라는 변수로 갑니다 저 노란색 아이콘들은 이젠 너무 작아 보이지 않죠 다양한 아이콘들의 다른 변수가 제가 조사 중인 엘리먼트를 위해 사용되지 않으면 새로운 CSS 도구로 사라집니다 하지만 걱정하지 마세요 필요할 때 보이게 해줄 버튼이 있으니까요 아마 올해 Web Inspector에서 가장 재미있는 부분일 텐데 Safari Web Inspector를 위한 개발자 도구 확장을 지원하게 되어 기쁩니다 여러분이 가장 좋아하는 개발자 도구 확장 버전 창시자들은 다른 브라우저에서 사용하는 다 같은 근본 API를 이용해 Safari에 복사하려고 합니다 Web Inspector에서 어떻게 확장하는지 배우는데 흥미가 있다면 새로운 API를 둘러보고 스스로 사용을 시작할 준비를 하시고 올해 WWDC의 'Safari Web Inspector 확장 프로그램 만들기'를 꼭 보세요 이제 우리가 최신 기술의 상당 부분과 새로운 걸 다뤘으니 주제를 바꿔서 웹 API의 새로운 점을 함께 살펴봅시다 Web Push 지원 기능을 알려드리게 되어 정말 기쁩니다 macOS Ventura의 Safari 16에서 가능할 겁니다 내년에는 iOS와 iPadOS에서도 가능합니다 Web Push는 멀리서도 웹사이트나 웹 앱에서 사용자들에게 통지를 보내게 해줍니다 완전히 상호 운용할 수 있는 표준 규격 기반 실행입니다 이미 Web Push를 실행했다면 다른 브라우저에서 작동한다면 어떠한 수정 없이도 Safari에서 작동해야 합니다 Apple Developer 계정도 필요하지 않습니다 자세한 내용을 전부 알고 싶다면 WWDC22의 'Safari의 웹 푸시 소개'를 보세요 Web Push에 설렜다면 아마 새로운 웹 앱 매니페스트 개선사항에도 설렐 거예요 이제 매니페스트 파일에서 홈 화면에 웹 앱을 저장할 때 쓰는 아이콘을 정의할 수 있습니다 매니페스트가 우선인 아이콘을 가지려면 HTML 헤드에 정의된 apple-touch-icon이 없다는 걸 확실히 해야 합니다 iOS와 iPadOS에 아이콘 하나를 보이게 하고 싶고 다른 모바일 플랫폼에는 다른 아이콘을 선보이고 싶다면 apple-touch-icon을 사용한 HTML 헤드에서 Apple 기기 아이콘을 정의해 선보이면 됩니다 어디서도 아이콘을 선언하지 않는다면 사용자가 여러분 사이트를 홈 화면에 저장할 때 사이트에서 간단하게 스크린숏을 얻을 수 있습니다 재미있는 건, 더는 사용자가 공유 메뉴에서 매니페스트 파일을 로드하려고 '홈 화면에 추가'를 선택하길 기다리지 않는데 매니페스트 파일이 여러분의 모든 사이트의 웹페이지 특성을 규정하고 메타 태그의 사용 필요성을 줄인다는 겁니다 API와 계속 함께하면서 많은 개선을 했습니다 같은 원본으로 된 여러 브라우징 컨텍스트의 웹 페이지 사용에서요 방송 채널은 다른 브라우징 컨텍스트 사이에서 알림을 보내게 해줍니다 누가 의류 교환 웹사이트를 사용하는데 동시에 창 두 개를 열었다고 생각해 봅시다 그러고 나서 창 하나에서 의류 한 점을 요청합니다 다른 열린 탭이나 창에 메시지를 게시하고 가능하지 않은 상태를 게시할 수 있게 됩니다 배경의 탭에서 업데이트 중이 아니더라도 업데이트하는 파일은 사이트에 저장되었습니다 사이트 저장을 위해 File System Access API에 기능을 추가했습니다 원본에 근거한 프라이빗 저장소인 원본 프라이빗 파일 시스템을 시작으로 올해 여러 번의 릴리즈를 통해 이 API에 점차적으로 업데이트했습니다 그러면 예를 들어 제 의류 교환 사이트는 apple.com처럼 파일을 읽는 다른 사이트를 갖지 않을 겁니다 그리고 API에 FileSystemFileHandle로 getFile() 방법을 추가했는데 사이트 루트 디렉터리에서 회수된 기존 파일을 읽는 방법입니다 방금 여기서 생성한 드래프트 파일을 가지고 파일을 읽는 것처럼요 이제 올해 가장 강렬한 API 추가사항을 새로운 풍성한 컬러로 함께 살펴봅시다 Display P3 색 공간은 RGB에 존재하지 않는 색을 표현할 수 있게 해줍니다 여기 컬러 피커의 예시가 있습니다 왼쪽의 구불구불한 흰 선은 RGB에 존재하는 색입니다 선의 오른쪽은 P3에서만 가능한 색입니다 2016년 동영상과 사진에 P3 지원을 추가했습니다 CSS 컬러 4단계에서 규정된 새로운 컬러 구문을 실행하기 위한 첫 브라우저 엔진이 되었기에 작년에 매우 신났습니다 올해는 캔버스 요소 내의 콘텐츠에 P3 컬러 지원을 추가했습니다 그러니 90년대의 기기에 기반한 색상을 사용할 필요가 없고 이제 현대의 모든 근사한 기기의 풀 컬러 기능 사용을 시작할 수 있습니다 하지만 작년부터 새로운 웹 API에 확인할 사항이 많은데 작년부터 shadow realm web lock ResizeObserverSize 인터페이스를 위해 업데이트 지원된 ResizeObserver API를 포함해 여러분이 엘리먼트의 박스 사이징 속성을 관찰하고 바꾸는 데 도움을 줄 겁니다 새 API 추가사항을 비롯해 테스트해 볼 게 많고 물론 우리의 새 특징들도 그렇습니다 사실 여전히 다룰 부분이 많습니다 이제 다음으로 JavaScript와 WebAssembly의 새로운 기능을 만나봅시다 여러분이 웹사이트를 사용하고 탭과 창을 가로질러 이 근로자들이 인스턴스를 공유하길 바란다면 새로운 SharedWorker 인터페이스가 잠재적으로 메모리 사용을 줄이는 데 도움을 줄 겁니다 배경에서 일어나길 원하는 모든 태스크에 새 근로자들을 배정하는 대신 한 명의 근로자가 같은 원본의 브라우징 컨텍스트를 사용하게 할 수 있습니다 각 스크립트는 같은 방식으로 SharedWorker를 만들고 같은 포트를 이용해 메시지를 수신하고 게시할 수 있습니다 SharedWorker는 모든 다른 스크립트에서 보낸 메시지를 수신하고 응답할 수 있게 됩니다 이러면 서버의 수요가 줄어드는 반면 여러분의 웹페이지는 고객들에게 신속하게 즉각 반응하게 됩니다 또한 여러분에게 보여줄 기능이 줄을 서 있습니다 reverse()를 사용하여 배열을 변형하는 대신 끝부터 검색하고 싶을 때 findLastIndex()와 findLast() 방법을 쓸 수 있습니다 아까 제가 'shoestring'을 포함한 품목과 인덱스를 찾을 때 했던 것처럼요 새로운 at() 방법 또한 배열의 끝부터 훨씬 쉽게 검색하도록 해줍니다 인덱스가 양수일 땐 브레이스를 사용하면 좋지만 at()으로는 코드를 더 간결하고 가독성 있게 만드는 음수값으로 검색하는 추가 기능을 얻을 수 있습니다 하지만 새로운 배열 특성의 좋은 숫자들이 있어도 우리가 마련한 새로운 국제화 특성의 순전한 숫자에 비할 바는 아닙니다 WebKit은 작년 내내 Intl 이행을 위해 계속 정기 업데이트를 했습니다 NumberFormat의 새로운 방법 Locale의 업데이트 덕인 캘린더 DisplayName과 Intl Enumeration API와 통화로 다른 숫자 시스템을 위한 지원이 추가되었습니다 제가 말씀드렸듯이 올해 우리의 Intl 구현에 많은 부분이 추가되어서 여러분의 사용자들이 충족하도록 시도해보고 탐험하는데 아무런 부족함이 없을 겁니다 웹에 가져오고 싶은 C Objective-C나 Swift와 같은 여러 코딩 언어로 된 모든 종류의 기존 코드를 다시 쓸 필요 없이 WebAssembly가 구동되게 해줍니다 올해의 개선사항으로 WebAssembly를 사용한 웹 앱은 4GB로 확장된 기억 장치로 더 강력해졌을 뿐만 아니라 성능을 확보해서 조작을 제외하고는 비용이 들지 않습니다 전체적으로 JavaScript와 WebAssembly로 해보기에 재미있는 것들이 좀 있습니다 WebAssembly이 나와서 말인데 일부 보안 및 프라이버시 개선도 해서 우리의 개발 대상인 웹 사용자들을 보호할 뿐만 아니라 개발자인 여러분에게 새로운 잠재력도 줄 겁니다 새로운 Cross Origin Opener Policy와 Cross Origin Embedder Policy HTTP 반응 헤더로 여러분 사이트를 고립 처리하게 참여시킬 수 있는데 특정한 작업용으로 만들어진 고유 webContent 프로세스에서 구동할 수 있다는 뜻입니다 우리는 WebAssembly 스레딩을 사용해 평행으로 다중 스레드를 구동해서 이득인 앱이 많다는 걸 압니다 이 새로운 헤더들로 그렇게 안전하게 할 수 있어요 우리의 두 번째 보안 개선은 HTTP 헤더 콘텐츠 보안 규정 3단계 지원 개선과도 연관이 있습니다 로딩 콘텐츠와 교차 사이트 스크립팅 다른 취약성에 대해서 CSP는 높아진 보안 컨트롤을 제공합니다 3단계 업데이트로 가장 흥미로운 추가사항인 새로운 strict-dynamic 소스 표현이 되었습니다 strict-dynamic의 디자이너는 특정 스크립트를 허용하려고 여러분이 임시값을 사용할 수 있다는 걸 깨달았고 이미 신뢰했던 값으로 스크립트를 로드하는데 신뢰를 확장했습니다 명백한 허용 리스트는 필요하지 않습니다 헤더가 얼마나 단순해지는지 보세요 도메인의 원래 긴 목록으로 가면 잠재적으로 너무 많이 허용할 수 있습니다 이것으로 보안 및 프라이버시 특징을 마무리할게요 오늘 다룰 내용도 곧 끝을 바라보는데 여러분 스스로 훑어볼 게 더 많습니다 예를 들어 getUserDisplay() API WebRTC Perfect Negotiation requestVideoFrameCallback()으로 특정 Safari 창 캡처를 위한 지원을 포함해 미디어 업데이트를 했습니다 매니페스트 버전 3의 지원으로 웹 확장을 위해 많은 기능을 추가했을 뿐만 아니라 새로운 웹 확장 API도 잔뜩 있습니다 오늘 여기서 다룬 특징을 모두 깊이 알아보고 작년에 Safari와 WebKit에서 개발한 162가지의 특징과 개선사항을 모두 탐구하고 미래에 나올 기능들을 따라잡기 위해 Safari Technology Preview를 다운로드해서 우리의 릴리즈 노트 블로그 게시물 Web Inspector를 위한 확장 문서를 포함한 webkit.org의 모든 좋은 콘텐츠를 확인하여 웹 기술을 살펴보세요 언제나처럼 여러분의 버그 리포트를 제출해 어떤 생각을 하는지 뭘 기대하는지 알려주세요 WebKit에서 버그를 발견하거나 HTML, CSS, JavaScript DOM API에 관련됐거나 Web Inspector와 연관이 있다면 bugs.webkit.org의 WebKit 버그 추적 시스템으로 피드백을 보내주세요 Safari 인터페이스와 관련된 제안이나 버그 파일 문제는 Apple의 Feedback Assistant로 제출하세요 우리는 여러분 같은 웹 개발자가 Safari를 가지고 더 나은 성과를 얻게 하는 놀라운 기능을 더 선보이기를 고대하며 Safari Technology Preview를 내년에 선보이고 싶습니다 오늘 함께해 주셔서 감사합니다 WWDC에서 최고의 시간을 보내시길 바랍니다 이만 인사드릴게요! ♪
-
-
2:59 - Dialog element
<!-- <dialog> element --> <dialog method="dialog"> <form id="dialogForm"> <label for="givenName">Given name:</label> <input class="focus" type="text" name="givenName"> <label for="familyName">Family name:</label> <input class="focus" type="text" name="familyName"> <label> <input type="checkbox"> Can trade in person </label> <button>Send</button> </form> </dialog>
-
3:09 - Backdrop pseudo-class
/* ::backdrop pseudo-element */ dialog::backdrop { background: linear-gradient(rgba(233, 182, 76, 0.7), rgba(103, 12, 0, 0.6)); animation: fade-in 0.5s; } @keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }
-
3:53 - inert attribute
// inert attribute function switchToIndex(index) { this.items.forEach(item => item.inert = true); this.items[index].inert = false; this.currentIndex = index; }
-
4:22 - Lazy image loading
<img src="images/shirt.jpg" loading="lazy" alt="a brown polo shirt" width="500" height="600">
-
6:46 - Container Queries
/* Container queries */ .container { container-type: inline-size; container-name: clothing-card; } .content { display: grid; grid-template-rows: 1fr; gap: 1rem; } @container clothing-card (width > 250px) { .content { grid-template-columns: 1fr 1fr; } /* additional layout code */ }
-
8:05 - Cascade layers
/* Author Styles - Layer A */ @layer utilities { div { background-color: red; } } /* Author Styles - Layer B */ @layer customizations { div { background-color: teal; } } /* Author Styles - Layer C */ @layer userDefaults { div { background-color: yellow; } }
-
8:54 - :has() pseudo-class
<!-- :has() pseudo-class --> <style> form:has(input[type="checkbox"]:checked) { background: #ff927a; } </style> <form class="message"> <textarea rows="5" cols="60" name="text" placeholder="Enter text"></textarea> <div class="checkbox"> <input type="checkbox" value="urgent"> <label>Urgent?</label> </div> <button>Send Message</button> </form>
-
11:08 - Offset Path
/* offset-path */ :is(.blue, .teal, .yellow, .red) { offset-path: circle(9vw at 5vw 50%); } @keyframes move { 100% { offset-distance: 100%; } } /* Animation */ .clothing-header.clicked :is(.blue, .teal, .red, .yellow) { animation: move 1100ms ease-in-out; }
-
11:43 - scroll-behavior: auto
html { scroll-behavior: auto; }
-
12:09 - scroll-behavior: smooth
html { scroll-behavior: smooth; }
-
13:10 - :focus-visible & accent-color
/* :focus-visible & accent-color */ :focus-visible { outline: 4px solid var(--green); box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.3); } :root { accent-color: var(--green); }
-
14:50 - Font palette dark mode & light mode
/* Dark mode */ font-palette: dark; /* Light mode */ font-palette: light;
-
15:01 - Font palette custom colors
/* Dark mode */ font-palette: dark; /* Light mode */ font-palette: light; /* Custom colors */ @font-palette-values --MyPalette { override-colors: 1 yellow; } #logo { font-palette: --MyPalette; }
-
15:55 - CSS Grid
/* Grid to layout cards */ main { display: grid; grid-template-columns: repeat(auto-fit, minmax(225px, 1fr)); gap: 1rem; } /* Grid to layout each card’s content */ article { display: grid; grid-row: span 5; }
-
16:35 - Adding sub grid
/* Grid to layout cards */ main { display: grid; grid-template-columns: repeat(auto-fit, minmax(225px, 1fr)); gap: 1rem; } /* Grid to layout each card’s content */ article { display: grid; grid-row: span 5; /* Adding subgrid, tying them together */ grid-template-rows: subgrid; }
-
21:15 - Web App Manifest file icons
// Manifest file "icons": [ { "src": "orange-icon.png", "sizes": "120x120", "type": "image/png" } ]
-
21:29 - apple-touch-icon
<!-- HTML head --> <link rel="apple-touch-icon" href="blue-icon.png" />
-
22:36 - Broadcast Channel
// State change broadcastChannel.postMessage("Item is unavailable");
-
23:14 - Origin private file system
// Accessing the origin private file system const root = await navigator.storage.getDirectory(); // Create a file named Draft.txt under root directory const draftHandle = await root.getFileHandle("Draft.txt", { "create": true }); // Access and read an existing file const existingHandle = await root.getFileHandle("Draft.txt"); const existingFile = await existingHandle.getFile();
-
25:32 - Shared Worker
// Create Shared Worker let worker = new SharedWorker("SharedWorker.js"); // Listen for messages from Shared Worker worker.port.addEventListener("message", function(event) { console.log("Message received from worker: " + event); }); // Send messages to Shared Worker worker.port.postMessage("Send message to worker");
-
25:56 - findLast() and findLastIndex()
const list = ["shirt","pants","shoes","hat","shoestring","dress"]; const hasShoeString = (string) => string.includes("shoe"); console.log(list.findLast(hasAppString)); // shoestring console.log(list.findLastIndex(hasAppString)); // 4
-
26:17 - at()
const list = ["shirt","pants","shoes","hat","shoestring","dress"]; // Instead of this: console.log(list[list.length - 2]); // It's as easy as: console.log(list.at(-2));
-
29:12 - strict-dynamic source expression
// strict-dynamic source expression // Without strict-dynamic Content-Security-Policy: script-src desired-script.com dependent-script-1.com dependent-script-2.com dependent-script-3.com; default-src "self"; // With strict-dynamic Content-Security-Policy: default-src "self"; script-src "nonce-desired" "strict-dynamic";
-
-
찾고 계신 콘텐츠가 있나요? 위에 주제를 입력하고 원하는 내용을 바로 검색해 보세요.
쿼리를 제출하는 중에 오류가 발생했습니다. 인터넷 연결을 확인하고 다시 시도해 주세요.