인라인으로 된 공유하기 메뉴는 어떻게 코딩할까?
Korean (한국어) translation by Jin Ah Chon (you can also view the original English article)
이번 튜토리얼에서 우리는 소위 "인라인으로 된 공유하기 메뉴"의 제작 방법을 학습할 것입니다. 이 인터페이스는 독자가 페이지를 공유하고, 하이라이트 표시된 텍스트를 인용할 수 있는 메뉴를 띄우는 방식으로 동작합니다. 여러분은 Medium처럼 몇몇 유명한 사이트에서 이와 유사한 인터페이스를 발견할 것입니다.
공유하기 메뉴 제작을 시작하기 전에 Medium에서 유사한 인터페이스가 어떻게 동작하는지, 예를 들어 화면에 나타나 하이라이트 된 영역보다 어느 위치에 있는지, 좀 더 세밀하게 검토해 보겠습니다. 이는 우리가 기술적인 면에서 적절한 인사이트를 얻고, 스스로 코드를 작성하는 방법을 결정하게 해주는 유용한 과정입니다.
시작해보죠!
Medium 인터페이스 검토
아래 이미지에서 Medium에 있는 공유하기 메뉴가 하이라이트 된 텍스트의 중간에 있는 것을 볼 수 있습니다. 선택해서 하이라이트 된 길이가 한 단어이거나 한 문장 혹은 문단 전체인지 상관없이 말이죠.



크롬 개발자 도구에서 작성된 스타일을 보면, 공유하기 메뉴 위칫값이 인라인 스타일에서 top
과 left
속성을 통해 주어졌음을 알게 됩니다. 또한, 변경자(modifier) class인 highlightMenu--active
를 적용해 공유하기 버튼이 눈에 보이게 된다는 것을 알 수 있습니다.
메모: 여러분이 변경자(Modifier)와 블록(Block), 요소(Element) 용어를 잘 모른다면, 이전 튜토리얼인 BEM 방법론 소개를 읽어보시기 바랍니다.



Styles 탭에서 보면, CSS로 초기 위치를 absolute
position으로 잡았고, z-index
속성은 페이지에서 다른 요소들보다 위에 올라가며, top
과 visibility
속성을 이용해 공유 버튼이 눈에 보이지 않게 설정하고 있음을 알 수 있습니다.
고로 우리가 해야 할 작업을 요약하자면,
- 선택된 부분의 중간 지점을 정할 수 있도록 선택된 영역의 길이를 가져오기
- 요소가 눈에 보이도록 변경자(modifier) 생성하기
- inline 스타일로 추가된
top
과left
속성을 이용해 공유하기 메뉴의 위치 설정하기
공유하기 메뉴 제작
예제에서 페이스북과 트위터 버튼이 공유하기 메뉴에 들어갑니다. 페이스북과 트위터 아이콘을 SVG 형태로 전달하고, button
과 소수의 div
요소를 이용해 아이콘을 감싸줍니다. 그리고 앞에서 본 코드에서 알 수 있듯이, 메뉴 아래에 삼각형 조각을 만드는 span
를 추가합니다.
1 |
<div class="sharing"> |
2 |
<div class="sharing__buttons"> |
3 |
<button id="share" title="Share"> |
4 |
<svg class="icon icon--facebook" version="1.1" xmlns="https://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512; width: 24px; height: 24px" xml:space="preserve"><g></g><g><g><path d="M426.8,64H85.2C73.5,64,64,73.5,64,85.2l0,341.6c0,11.7,9.5,21.2,21.2,21.2H256V296h-45.9v-56H256v-41.4 c0-49.6,34.4-76.6,78.7-76.6c21.2,0,44,1.6,49.3,2.3v51.8l-35.3,0c-24.1,0-28.7,11.4-28.7,28.2V240h57.4l-7.5,56H320v152h106.8 c11.7,0,21.2-9.5,21.2-21.2V85.2C448,73.5,438.5,64,426.8,64z"/></g></g></svg> |
5 |
</button>
|
6 |
<button id="tweet" title="Tweet"> |
7 |
<svg class='icon icon--twitter' version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 512 512' style='enable-background:new 0 0 512 512; width: 24px; height: 24px' xml:space='preserve'><path d='M492,109.5c-17.4,7.7-36,12.9-55.6,15.3c20-12,35.4-31,42.6-53.6c-18.7,11.1-39.4,19.2-61.5,23.5 |
8 |
C399.8,75.8,374.6,64,346.8,64c-53.5,0-96.8,43.4-96.8,96.9c0,7.6,0.8,15,2.5,22.1c-80.5-4-151.9-42.6-199.6-101.3
|
9 |
c-8.3,14.3-13.1,31-13.1,48.7c0,33.6,17.2,63.3,43.2,80.7C67,210.7,52,206.3,39,199c0,0.4,0,0.8,0,1.2c0,47,33.4,86.1,77.7,95c-8.1,2.2-16.7,3.4-25.5,3.4c-6.2,0-12.3-0.6-18.2-1.8c12.3,38.5,48.1,66.5,90.5,67.3c-33.1,26-74.9,41.5-120.3,41.5
|
10 |
c-7.8,0-15.5-0.5-23.1-1.4C62.8,432,113.7,448,168.3,448C346.6,448,444,300.3,444,172.2c0-4.2-0.1-8.4-0.3-12.5
|
11 |
C462.6,146,479,129,492,109.5z'/> |
12 |
</svg>
|
13 |
</button>
|
14 |
</div>
|
15 |
<span class="sharing__triangle"></span> |
16 |
</div>
|
메뉴 색상과 모양에 관해 결정된 규칙은 없습니다. 여러분의 사이트 디자인과 일치하는 메뉴로 자유롭게 꾸미세요. 버튼 크기 즉, 높이와 너비는 관심을 둘 만합니다. 여기 공유하기 메뉴는 아래 이미지에서 보이는 것처럼 너비가 84px
이고 높이가 40px
입니다. 나중에 공유하기 메뉴를 하이라이트 된 영역의 중간에 위치를 잡는 데 이 두 값을 사용할 것입니다.



초기 position과 visibility를 설정하는 스타일 코드입니다.
1 |
.sharing { |
2 |
position: absolute; |
3 |
visibility: hidden; |
4 |
top: 0; |
5 |
left: 0; |
6 |
z-index: 500; |
7 |
}
|
그리고 마지막에 공유하기 버튼을 눈에 보이게 하려고 붙이는 class입니다.
1 |
.sharing--shown { |
2 |
visibility: visible; |
3 |
}
|
공유하기 메뉴의 함수 제작
이 시점에 인라인 공유하기 메뉴는 페이지에서 눈에 보이지 않아야 합니다. 또한, 페이스북과 트위터 버튼을 클릭할 때도 공유하기 윈도우 창은 어디에서도 보이지 않습니다. 자, 이 섹션에서 우리가 생각한 대로 버튼이 동작하도록 자바스크립트를 작성하겠습니다. 아래의 getHighlight()
함수로 시작합니다.
1 |
function getHighlight() { |
2 |
|
3 |
var selection = window.getSelection(); // 1. |
4 |
|
5 |
var object = { |
6 |
parent : null, |
7 |
text : '', |
8 |
rect : null |
9 |
};
|
10 |
|
11 |
// If selection is not empty.
|
12 |
if ( selection.rangeCount > 0 ) { |
13 |
object = { |
14 |
text : selection.toString().trim(), // get the text. |
15 |
parent : selection.anchorNode.parentNode, // get the element wrapping the text. |
16 |
rect : selection.getRangeAt(0).getBoundingClientRect() // get the bounding box. |
17 |
};
|
18 |
}
|
19 |
|
20 |
return object; // 2. |
21 |
}
|
이 함수는 다음과 같이 진행됩니다.
- 네이티브 자바스크립 함수인
getSelection()
을 이용해 하이라이트 된 영역을 가져옵니다. - 선택된 텍스트와 텍스트를 감싸는 요소와 선택된 영역의 Rectangle Object를 담고 있는 Object를 받아넘깁니다. Rectangle Object는 페이지 내 선택된 영역의 크기와 위치(
top
,bottom
,left
,right
) 값을 줍니다.
다음 함수는 showMenu()
라고 명명하겠습니다. 이름에서 짐작 가듯이, 이 함수는 공유하기 메뉴를 눈에 보이게 합니다.
1 |
var sharing = document.querySelector( '.sharing' ); |
2 |
|
3 |
function showMenu() { |
4 |
|
5 |
// 1.
|
6 |
var highlight = getHighlight(); |
7 |
|
8 |
// 2.
|
9 |
if ( highlight.text === '' ) { |
10 |
|
11 |
sharing.setAttribute( 'class', 'sharing' ); |
12 |
sharing.style.left = 0; |
13 |
sharing.style.top = 0; |
14 |
|
15 |
return; |
16 |
}
|
17 |
|
18 |
// 3.
|
19 |
/**
|
20 |
* Only show the sharing button if the selected is a paragraph.
|
21 |
*/
|
22 |
if ( highlight.parent.nodeName !== 'P' ) { |
23 |
return; |
24 |
}
|
25 |
|
26 |
// 4.
|
27 |
var width = ( highlight.rect.width / 2 ) - 42; |
28 |
/**
|
29 |
* The "42" is acquired from our sharing buttons width devided by 2.
|
30 |
*/
|
31 |
|
32 |
sharing.setAttribute( 'class', 'sharing sharing--shown' ); |
33 |
sharing.style.left = ( highlight.rect.left + width ) + 'px'; |
34 |
sharing.style.top = ( highlight.rect.top - 40 ) + 'px'; |
35 |
/**
|
36 |
* "40" is the height of our sharing buttons.
|
37 |
* Herein, we lift it up above the higlighted area top position.
|
38 |
*/
|
39 |
}
|
이 함수에 작성된 코드는 구체적으로 다음과 같이 진행됩니다.
-
getHighlighted()
함수에서 Object를 받습니다. - 하이라이트 된 영역에 텍스트가 들어 있지 않고 비어 있다면, 공유하기 메뉴를 숨기고 초기 위치로 설정합니다.
- 하이라이트 된 텍스트가 단락 안에 싸여있지 않다면 버튼을 눈에 보이지 않게 합니다.
- 마지막에
top
과left
position을 설정하고 공유하기 버튼이 눈에 보이도록sharing--shown
class를 붙입니다. 저는 몇몇 숫자의 출처가 어디인지 설명하는 주석도 코드에 추가로 작성하였습니다.
대다수의 사용자가 마우스를 사용해 웹에서 콘텐츠를 하이라이트 한다고 가정하겠습니다. 그래서 이 함수를 mouseup
이벤트에 바인딩(bind)합니다. 모바일 기기에서는 보통 자체적으로 텍스트를 선택하는 콘텍스트 메뉴(contextual menu)가 있으므로 이 튜토리얼에서는 웹에 중점을 두겠습니다.



콘텐츠가 적절하게 선택되도록 setTimeout()
함수를 이용해 100ms
만큼 실행을 지연합니다.
1 |
document.body.addEventListener( 'mouseup', function() { |
2 |
setTimeout( showMenu, 100 ); |
3 |
} ); |
마지막 함수인 openShareWindow()
는 메뉴에 있는 버튼을 클릭할 때 공유하기 창을 열어줍니다. 페이스북에는 자체의 자바스크립트 SDK가 있으므로 이번 튜토리얼에서는 기본적으로 이 함수를 트위터 공유하기 창으로 전달하는 데 사용할 것입니다.
1 |
function openShareWindow( url, w, h ) { |
2 |
|
3 |
var screenLeft = window.screenLeft !== undefined ? window.screenLeft : screen.left; |
4 |
var screenTop = window.screenTop !== undefined ? window.screenTop : screen.top; |
5 |
var width = window.innerWidth ? window.innerWidth : doc.documentElement.clientWidth ? doc.documentElement.clientWidth : screen.width; |
6 |
var height = window.innerHeight ? window.innerHeight : doc.documentElement.clientHeight ? doc.documentElement.clientHeight : screen.height; |
7 |
|
8 |
var left = ( ( width / 2 ) - ( w / 2 ) ) + screenLeft; |
9 |
var top = ( ( height / 2 ) - ( h / 2 ) ) + screenTop; |
10 |
|
11 |
var newWin = window.open( url, "", "scrollbars=no,width=" + w + ",height=" + h + ",top=" + top + ",left=" + left ); |
12 |
|
13 |
if ( newWin ) { |
14 |
newWin.focus(); |
15 |
}
|
16 |
}
|
클릭...클릭...
다음에는 공유 버튼을 click
이벤트와 바인딩하고 공유하기 창을 띄울 함수를 덧붙입니다.
1 |
// Facebook.
|
2 |
document.getElementById( 'share' ).addEventListener( 'click', function() { |
3 |
|
4 |
var highlight = getHighlight(); |
5 |
|
6 |
if ( highlight.text !== '' && highlight.parent.nodeName === 'P' ) { |
7 |
FB.ui({ |
8 |
method : 'share', |
9 |
mobile_iframe: true, |
10 |
href : 'http://bitly.com/2aiHmCs', |
11 |
quote : highlight.text // pass the text as Quote |
12 |
});
|
13 |
}
|
14 |
|
15 |
event.preventDefault(); |
16 |
} ); |
페이스북 공유 버튼에는 페이스북의 자바스크립트 SDK를 사용합니다. SDK에서는 quote
매개 변수를 통해 공유하기 창에 보일 텍스트를 전달할 수 있습니다.



트위터에서는 그와 같은 방식으로 된 자바스크립트 SDK를 제공하지 않습니다. 그래서 우리는 openShareWindow()
함수를 이용해 창 크기와 함께 트위터 가이드라인을 따르고 정형화된 URL을 전달합니다.
1 |
document.getElementById( 'tweet' ).addEventListener( 'click', function() { |
2 |
|
3 |
var highlight = getHighlight(); |
4 |
|
5 |
if ( highlight.text !== '' && highlight.parent.nodeName === 'P' ) { |
6 |
|
7 |
var docURL = encodeURIComponent( 'http://bitly.com/2aiHmCs' ); |
8 |
var tweetText = encodeURIComponent( highlight.text ); |
9 |
var tweetURL = 'https://twitter.com/intent/tweet?via=wdtuts&url=' + docURL + '&text=' + tweetText; |
10 |
|
11 |
openShareWindow( tweetURL, 600, 420 ); |
12 |
}
|
13 |
|
14 |
event.preventDefault(); |
15 |
} ); |
트위터 공유하기 버튼을 클릭하면 창이 열리며 다음과 같은 화면이 보입니다.



마무리
인라인으로 된 공유하기 메뉴 제작 과정을 모두 마쳤습니다! 함수로 꽉 차있는 소스 코드나 제대로 동작하는지 확인하러 데모로 가 보세요. 다음에는 더 매력적인 경험을 전달하도록 transition이나 animation을 이용해 인라인 공유하기 메뉴를 향상시킬 수 있습니다.
그 외의 참고자료
공유하기 메뉴를 띄우고 동작하는 데 사용했던 몇 가지 자바스크립트 API가 있습니다. 이 중에 일부는 Envato Tuts+ 튜토리얼에서 이전에 언급한 적이 있습니다. 나머지는 여러분에게 생소할 것 같습니다. 다음은 제가 이 튜토리얼을 보완하는 데 참고했던 자료입니다.