Outsider's Dev Story

Stay Hungry. Stay Foolish. Don't Be Satisfied.

HTML 요소에서 마우스 이벤트 받지 않기

작년에 Summernote 웹사이트를 작업할 때 디자인에 따라 Summernote 에디터 위에 플레이스 홀더처럼 보이는 DIV를 위에 올려야 했다. 섬머노트에 플레이스 홀더 기능이 있지만, 이는 텍스트 에디터의 기능적인 것이므로 웹사이트에서는 커다란 글자의 플레이스 홀더를 앞에 보여주고 에디터를 클릭하거나 하면 이를 감추도록 작업을 했다.

Summernote 홈페이지의 화면

에디터에 onFocus 이벤트를 등록해서 에디터를 잘 클릭하면 플레이스 홀더를 감추는 게 어렵지 않지만, 에디터 위에 <div>가 있으므로 이 <div>를 클릭하면 에디터가 클릭 되지 않아서 이벤트가 발생하지 않았다. <div>에서 이벤트를 받아서 수동으로 에디터의 onFocus 이벤트를 실행해도 되지만 기능이 필요한 것은 아니므로 아예 이벤트를 안 받게 하고 싶었다.

이는 CSS의 pointer-events를 이용하면 해결할 수 있다.

pointer-events: none;

해당 <div>pointer-events: none;로 설정하면 이 <div>는 마우스의 타겟이 되지 않는다. 눈에는 보이지만 마우스 타겟이 아니므로 위 화면에서도 플레이스 홀더를 클릭해도 이벤트는 Summernote 에디터가 받게 된다.

Caniuse의 브라우저 지원 표

참고로 이 속성은 IE 10 이하에서는 동작하지 않는다.

2016/05/28 18:07 2016/05/28 18:07

Schema.org로 웹 콘텐츠 구조화하기

Schema.org라는 이니셔티브가 있다. Schema.org의 존재에 대해서는 오랫동안 알고 있었지만, 딱히 사용해 보지는 않고 있었다. 구글의 웹 마스터 도구에서 계속 구조화된 데이터(Structured Data)가 없다고 계속 안내가 나와서 맘먹고 적용을 해보았다. Schema.org와 관련된 내용도 다양하고 구글에서 사용하는 용어도 약간 차이가 있고 해서 처음에 볼 때는 엄청 헷갈렸다.

Schema.org

언제였는지는 기억 안 나지만 페이스북은 서비스 내에서 웹페이지를 카드 형태로 보여주기 위해서 오픈 그래프를 사용하기 시작했다. 페이스북이 오픈 그래프라는 말을 다양하게 쓰고 있기는 한데 여기서는 웹사이트 상단에 <meta property="og:title" content="">처럼 사용하는 메타 태그를 의미한다. 오픈 그래프가 없어도 웹페이지에서 제목과 사진 등을 가져올 수 있지만 정확하지 않은 경우도 많으므로 개발자가 카드에 표시될 내용을 메타 태그로 지정할 수 있게 한 것이다. 덕분에 웹페이지 개발자의 의도대로 제목과 콘텐츠 등을 정확하게 보여줄 수 있게 되었고 오픈 그래프의 접근이 유효하다고 판단되자 트위터는 Twitter Cards를 만들어서 비슷하게 사용하고 있다.

뉴욕타임스의 메타 태그

위는 뉴욕타임스 기사의 메타 태그인데 전부 오픈 그래프나 트위터 카드를 위한 메타 태그는 아니지만 콘텐츠 중심의 사이트는 다양한 회사의 요구사항을 맞추기 위해서 메타 태그를 엄청나게 넣어야 하는 상황이 되었다. 딴 얘기지만 이제 메타 태그를 모아주는 manifest 파일을 따로 지정하는 접근이 필요하지 않나 생각한다.

어쨌든 Google이 오픈 그래프를 그대로 쓰기는 어렵고 검색엔진은 오픈 그래프나 트위터 카드의 요약 정보 이상의 내용이 필요하므로 MS, Yahoo!와 함께 schema.org를 발표하게 된다.1 schema.org는 웹페이지의 정보를 구조화해서 검색엔진이 더 정확하게 분석할 수 있게 한 것으로 그 안에는 다양한 명세가 포함되어 있다. 이는 과거 시맨틱웹이라는 이름으로 웹페이지를 구조화하려던 시도와 같은 목적이라고 보고 있다. 그 당시에는 시맨틱웹이라는 용어 자체가 버즈워드였고 이제는 그렇지 않지만 다른 접근을 취한 것이라고 보인다. 구글의 웹 마스터 도구에서도 이쪽은 강조하고 있지만 이번에 적용하면서 자료 찾아봐도 적용한 곳이 많지는 않아서 얼마나 잘 쓰이고 있는지는 모르겠다.

관련 용어

적용하려고 처음 볼 때 한꺼번에 너무 많은 용어가 나와서 내용을 이해하기가 어려웠다. 그래서 용어를 먼저 정리해 볼까 한다.

schema.org

schema.org를 운영하는 이니셔티브의 이름이면서 동시에 구조화된 데이터의 vocabulary다. vocabulary라고 부르는 이유는 schema.org는 구조화된 데이터에서 사용하는 용어만 정의하고 있고(예를 들어 글은 Article 같은 식으로...) 실제 사용하는 기술을 따로 있기 때문이다. 현재 Microdata, RDFa, JSON-LD의 형식 중 하나를 사용해서 schema.org를 표현할 수 있다.

구조화된 데이터(structured data)

이는 구글이 사용하는 용어인데 구글에서 얘기하는 구조화된 데이터는 현재 Schema.org를 사용하고 있다. 기술은 계속 달라질 수도 있으므로 웹페이지를 텍스트 기반으로 분석하기 쉽게 만드는 접근을 "구조화된 데이터"라고 정의해 놓고 현재는 schema.org를 지원하고 있다는 식으로 사용하고 있다.

리치 스니펫(Rich Snippets)

리치 스니펫은 구글에서 검색 결과를 보여줄 때 제목과 내용 외에 좀 더 상세한 내용이 나오는 것을 의미한다. 웹페이지에서 구조화된 데이터를 제공하면 이 리치 스니펫을 사용하고 있다. 최근에는 구글이 AMP를 밀고 있어서 리치 카드라는 것이 새로 나왔고 리치 스니펫도 카드 형태 비슷했지만, AMP를 이용한 리치 카드를 더 미는 느낌이다. 문서에서도 리치 스니펫이랑 용어도 대부분 줄이고 리치 카드 쪽으로 모는 느낌이다.

Microdata

Microdata는 HTML 마크업의 속성으로 메타데이터를 지정하는 방법으로 W3C 명세이다.

<div itemscope itemtype="http://schema.org/Movie">
  <h1 itemprop="name">Ghostbusters</h1>
  <div itemprop="productionCompany" itemscope itemtype="http://schema.org/Organization">
    Produced by: <span itemprop="name">Black Rhino</span><p>
  </div>
  <div itemprop="countryOfOrigin" itemscope itemtype="http://schema.org/Country">
    Country: <span itemprop="name" content="USA">United States</span><p>
  </div>
</div>

위와 같이 기존 HTML 태그에 해당 부분이 어떤 정보인지를 표시하는 식으로 사용한다. 그래서 검색엔진은 이 부분이 영화정보이고 Ghostbusters가 영화 제공이고 영화사는 Black Rhino이면서 미국 영화라는 것을 알 수 있다. 텍스트만으로는 검색엔진이 이런 의미를 정확하기 파악하기가 어려우므로 마크업에서 정보를 제공하면 검색엔진이 그에 맞게 검색결과를 제공한다는 것이다.

RDFa

RDFa는 Resource Description Framework in Attributes의 약자로 이름만 보아도 Microdata와 거의 차이가 없고 W3C의 명세이다. 똑같이 HTML 마케업에 속성으로 어떤 정보인지를 표시한다.

<div vocab="http://schema.org/" typeof="Movie">
  <h1 property="name">Ghostbusters</h1>
  <div property="productionCompany" typeof="Organization">
    Produced by: <span property="name">Black Rhino</span><p>
  </div>
  <div property="countryOfOrigin" typeof="Country">
    Country: <span property="name" content="USA">United States</span><p>
  </div>
</div>

그러면 Microdata와 RDFa는 뭐가 다른가 하는 궁금함이 남게 되는데 내가 찾아본 결과로는 몇 가지 차이점이 있다.

  • Microdata는 명세 작업이 거의 멈춘 상태이다. 지금은 별문제 없지만, 앞으로 나올 다른 요구사항에 대한 추가 작업을 기대하기 어렵다는 얘기이다.
  • Microdata는 HTML에서만 사용할 수 있지만 RDFa는 HTML 외 XML이나 SVG 같은 다른 마크업에서도 사용할 수 있다.
  • Microdata는 한 콘텐츠에서 하나의 vocabulary만 사용할 수 있지만 RDFa는 접두사가 있어서 여러 vocabulary를 섞어서 사용할 수 있다.

JSON-LD

JSON-LD는 JavaScript Object Notation for Linked Data의 약자로 여기서 Linked Data는 시맨틱웹을 얘기할 때 나오던 Linked Data인데 요즘은 이런 말을 하지 않지만 여기서는 크게 중요한 얘기도 아니다.

<script type="application/ld+json">
{
  "@context": "http://schema.org/",
  "@type": "Movie",
  "name": "Ghostbusters",
  "productionCompany": {
    "@type": "Organization",
    "name": "Black Rhino"
  },
  "countryOfOrigin": {
    "@type": "Country",
    "name": "USA"
  }
}
</script>

위처럼 application/ld+json 타입의 <script> 태그 안에서 데이터의 구조를 JSON으로 표현한다.

Schema.org를 적용해 보고 나서...

위의 내용을 이해하고 한두 개 적용해 보고 나면 Schema.org를 적용하는 것은 그다지 어렵지 않다. 기술적으로 대단한 내용은 없으므로 주로 고민하는 부분은 어떤 분류로 구조화를 하고 어떤 정보를 제공할 것인가 하는 부분 정도이다. 그래서 사용방법은 문서를 보면 되므로 어떻게 적용하는지 보여주기보다는 적용하고 나서 느끼게 된 점을 정리하는 게 나을 것 같다.

  • Microdata를 사용해서 이 블로그에 적용했다. 위에 Microdata와 RDFa를 비교한 것을 보면 RDFa를 사용하지 않을 이유가 없지만, 당시에는 둘 사이의 차이를 자세히 몰라서 제일 앞에 있는 Microdata를 사용했다. JSON-LD는 JSON으로만 표현하면 되니 자유롭지만, HTML에 있는 내용을 중복으로 한 번 더 표현해야 하므로 나는 낭비라고 생각해서 빼버렸다.
  • Schema에서 자신의 콘텐츠에 어울리는 타입을 찾아야 한다. 예를 들어 BlogPosting이나 Comment
  • HTML은 계층적 구조를 가지는데 여기서 원하는 부분이 어떤 타입을 지정한다고 itemtype="http://schema.org/Movie"와 같이 지정하게 된다. 이때 해당 부분이 별도의 영역이라는 의미로 itemscope 속성을 같이 써주게 되고 결과적으로 <div itemscope itemtype="http://schema.org/Movie">같은 형태가 된다.
  • 다른 속성 등은 itemprop를 사용한다. <span itemprop="name">Black Rhino</span>처럼 지정하면 안에 있는 텍스트를 그 값으로 사용하고 다른 텍스트를 제공하고 싶다면 <span itemprop="name" content="USA">United States</span>처럼 content를 사용하면 된다.
  • 한 문서에 여러 타입이 있을 수 있다. 예를 들어 Article로 본문을 지정하고 작성자 정보는 Person로 지정하고 이미지는 ImageObject와 같이 지정할 수 있다.
  • 구글 문서에 따르면 사람이 볼 수 있는 데이터만 검색엔진이 사용한다. 테스트는 안 해봤지만 CSS로 감추거나 화면에 보이지 않는 요소는 검색엔진이 가져가지 않는다고 한다. 대신 화면에는 없지만, 검색엔진에만 적용하고 싶은 경우가 생기는데 예를 들어 수정시간은 웹페이지에는 표시하지 않지만, 검색엔진에는 제공하고 싶은 경우에는 <meta itemprop="dateModified" content="2016/05/16 23:29">처럼 <meta>태그를 사용한다.
  • 반대로 구조화를 하다 보니 검색엔진에 제공하지 않고 싶은 정보가 생기게 된다. 예를 들어 블로그의 본문 영역을 articleBody로 지정했을 때 이 안에는 본문 외에도 좋아요 수라거나 댓글 수라거나 서비스에 따라 다양한 내용이 들어가게 되는데 이를 구조화해서 파싱했을 때 본문에 이런 내용이 들어가니까 이를 제거해서 깔끔하게 만들고픈 욕심이 생기게 된다. JSON-LD를 쓰면 가능하겠지만 Microdata나 RDFa에는 이런 방법이 없는 것 같다. 다시 생각해 보면 구조화하기 전에는 검색엔진이 HTML 전체를 가져갔으므로 거기에 약간의 정보를 추가할 뿐이지 그 이상으로 데이터를 정리할 필요는 없어 보인다. 그냥 큼직하게 알려주면 검색엔진이 알아서 한다. Medium같은 경우는 <body itemscope itemtype="http://schema.org/Article">처럼 바디에 정의하고 끝이다.(저렇게 하려면 안 해도 큰 상관 없어 보이는데...)
  • 명세와 다르게 구글은 이미지에 ImageObject만 지원한다. 명세상으로는 imageImageObjectURL이므로 <img> 태그에 바로 itemprop="image"와 같이 지정할 수 있어야 하는데 이렇게 하면 구글이 오류를 뱉어낸다. 다음과 같이 해야 한다.
<div itemprop="image" itemscope, itemtype="http://schema.org/ImageObject">
     <img src="path/to" itemprop="url">
     <meta itemprop="width" content="640">
     <meta itemprop="height" content="640">
</div>
  • image 외에도 publisher는 반드시 Organization이어야 한다는 등의 규칙이 있다.

문서가 잘 안되어있고 베스트 프렉티스도 많지 않아서 실제로 적용하면서 구글이 제공하는 Structured Data Testing Tool로 확인해보는 게 가장 편하고 빠른 것 같다. 이 도구에서 적용한 부분을 구글이 제대로 인식하는지, 오류가 있는지(오류의 원인은 친절하진 않다.)

구글의 구조화된 데이터 테스트 도구

1, 2주 전만 해도 이 도구에서 Article Rich Snippets와 AMP Articles를 나누어 보여주고 있었는데 둘을 합쳐버린 걸 보니 AMP를 미는 게 확실해 보인다. 참고로 저 오류는 Rich Snippets에서는 괜찮은데 AMP에서는 필수값이라고 오류가 나던 부분이었다.

웹 마스터 도구에서의 구조화된 데이터 수집 개수

구글 웹 마스터 도구를 보면 구조화된 데이터가 수집되기 시작한 것을 볼 수 있다. 실제로 검색 결과가 어떻게 달라지는지는 아직 모르겠다.


  1. 내 기억을 더듬은 내용이고 추측도 들어있으므로 정확한 인과관계는 아니다. 

2016/05/22 21:51 2016/05/22 21:51