diff options
author | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:42:17 -0500 |
---|---|---|
committer | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:42:17 -0500 |
commit | da78a9e329e272dedb2400b79a3bdeebff387d47 (patch) | |
tree | e6ef8aa7c43556f55ddfe031a01cf0a8fa271bfe /files/ko/learn | |
parent | 1109132f09d75da9a28b649c7677bb6ce07c40c0 (diff) | |
download | translated-content-da78a9e329e272dedb2400b79a3bdeebff387d47.tar.gz translated-content-da78a9e329e272dedb2400b79a3bdeebff387d47.tar.bz2 translated-content-da78a9e329e272dedb2400b79a3bdeebff387d47.zip |
initial commit
Diffstat (limited to 'files/ko/learn')
157 files changed, 45403 insertions, 0 deletions
diff --git a/files/ko/learn/common_questions/how_does_the_internet_work/index.html b/files/ko/learn/common_questions/how_does_the_internet_work/index.html new file mode 100644 index 0000000000..f75add9c5a --- /dev/null +++ b/files/ko/learn/common_questions/how_does_the_internet_work/index.html @@ -0,0 +1,93 @@ +--- +title: 인터넷은 어떻게 동작하는가? +slug: Learn/Common_questions/How_does_the_Internet_work +translation_of: Learn/Common_questions/How_does_the_Internet_work +--- +<div class="summary"> +<p>이 글에서는 인터넷의 개념과 작동 원리에 대해 설명합니다.</p> +</div> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">선행지식:</th> + <td>선행지식은 필요없습니다. 하지만 '프로젝트의 목표 설정에 대한 글(<a href="/en-US/docs/Learn/Thinking_before_coding">Article on setting project goals</a>)에 대한 글을 먼저 읽어보세요.</td> + </tr> + <tr> + <th scope="row">목적:</th> + <td><span id="result_box" lang="ko"><span>웹 기술 인프라의 기초와 인터넷과 웹의 차이점을 배우게 됩니다.</span></span></td> + </tr> + </tbody> +</table> + +<h2 id="요약">요약</h2> + +<p><strong>인터넷</strong>은 웹의 핵심적인 기술입니다. 인터넷의 가장 기본적인 것은, 컴퓨터들이 서로 통신 가능한 거대한 네트워크라는 것입니다.</p> + +<p><a href="http://en.wikipedia.org/wiki/Internet#History" rel="external">인터넷의 역사는 잘 알려지지 않았습니다</a>. 인터넷은 1960년 대 미육군에서 기금한 연구 프로젝트에서 시작되었습니다. 그리고 1980년 대에 많은 국립 대학과 비공개 기업의 지원으로 공공의 기반으로 변화되었습니다. <span id="result_box" lang="ko"><span>인터넷을 지원하는 다양한 기술은 시간이 지남에 따라 진화 해 왔지만 작동 방식은 그다지 변하지 않았습니다. 인터넷은 모든 컴퓨터를 연결하고 어떤 일이 있어도 연결 상태를 유지할 수있는 방법을 찾는 방법입니다.</span></span></p> + +<h2 id="활동적으로_배우기">활동적으로 배우기</h2> + +<ul> + <li><a href="https://www.youtube.com/watch?v=7_LPdttKXPc" rel="external">How the internet Works in 5 minutes</a>: Aaron Titus의 인터넷에 대한 기초를 이해하기 위한 5분짜리 동영상</li> +</ul> + +<h2 id="깊게_들어가기">깊게 들어가기</h2> + +<h3 id="단순한_네트워크">단순한 네트워크</h3> + +<p>두 개의 컴퓨터가 통신이 필요할 때, 우리는 다른 컴퓨터와 물리적으로 (보통 <a href="http://en.wikipedia.org/wiki/Ethernet_crossover_cable" rel="external">이더넷 케이블</a>) 또는 무선으로 (예를 들어, <a href="http://en.wikipedia.org/wiki/WiFi" rel="external">WiFi</a> 나 <a href="http://en.wikipedia.org/wiki/Bluetooth" rel="external">Bluetooth</a> 시스템) 연결되어야 합니다. 모든 현대 컴퓨터들은 이러한 연결 중 하나를 이용하여 연결을 지속할 수 있습니다.</p> + +<div class="note"> +<p><strong>Note:</strong> 이 글의 나머지 부분에서는 유선 케이블에 대해서만 이야기 하지만 무선 네트워크도 동일한 방식입니다.</p> +</div> + +<p><img alt="Two computers linked together" src="https://mdn.mozillademos.org/files/8441/internet-schema-1.png" style="height: 152px; width: 600px;"></p> + +<p>이러한 네트워크는 두 대의 컴퓨터로 제한되지 않습니다. 원하는 만큼의 컴퓨터를 연결할 수 있습니다. 그러나 이렇게 연결할 수록 매우 복잡해집니다. 예를 들어 10대의 컴퓨터를 연결하려는 경우 컴퓨터 당 9개의 플러그가 달린 45개의 케이블이 필요합니다!</p> + +<p><img alt="Ten computers all together" src="https://mdn.mozillademos.org/files/8443/internet-schema-2.png" style="height: 576px; width: 600px;"></p> + +<p><span id="result_box" lang="ko"><span>이 문제를 해결하기 위해 네트워크의 각 컴퓨터는 라우터라고하는 특수한 소형 컴퓨터에 연결됩니다.</span> <span>이 라우터에는 단 하나의 작업만 있습니다. 철도역의 신호원처럼 주어진 컴퓨터에서 보낸 메시지가 올바른 대상 컴퓨터에 도착하는지 확인합니다.</span> <span>컴퓨터 B에게 메시지를 보내려면 컴퓨터 A가 메시지를 라우터로 보내야하며, 라우터는 메시지를 컴퓨터 B로 전달하고 메시지가 컴퓨터 C로 배달되지 않도록해야합니다.</span></span></p> + +<p><span id="result_box" lang="ko"><span>이 라우터를 시스템에 추가하면 10대의 컴퓨터 네트워크에는 10개의 케이블만 필요합니다. 각 컴퓨터마다 단일 플러그와 10개의 플러그가 있는 하나의 라우터가 필요합니다.</span></span></p> + +<p><img alt="Ten computers with a router" src="https://mdn.mozillademos.org/files/8445/internet-schema-3.png" style="height: 576px; width: 600px;"></p> + +<h3 id="네트워크_속의_네트워크">네트워크 속의 네트워크</h3> + +<p>지금까지는 <span id="result_box" lang="ko"><span>그런대로 잘되었습니다.</span> <span>수백, 수천, 수십억 대의 컴퓨터를 연결하는 것은 어떨까요?</span> <span>물론 단일 라우터는 그 정도까지 확장 할 수는 없지만 신중하게 읽으면 라우터는 다른 컴퓨터와 마찬가지로 컴퓨터라고 말했습니다. 그럼, 두 대의 라우터를 연결하지 못하게 하는 것이 있을까요? 없죠!</span></span></p> + +<p><img alt="Two routers linked together" src="https://mdn.mozillademos.org/files/8447/internet-schema-4.png"></p> + +<p>컴퓨터를 라우터에 연결하고, 라우터에서 라우터로, 우리는 무한히 확장할 수 있습니다.</p> + +<p><img alt="Routers linked to routers" src="https://mdn.mozillademos.org/files/8449/internet-schema-5.png" style="height: 563px; width: 600px;"></p> + +<p><span id="result_box" lang="ko"><span>이러한 네트워크는 우리가 인터넷이라고 부르는 것에 매우 가깝지만, 우리는 뭔가를 놓치고 있습니다.</span> <span>우리는 우리의 목적을 가지고 네트워크를 구축했습니다. 하지만 그밖에 </span><span>다른 네트워크들 : 친구, 이웃, 누구든지 컴퓨터로 이루어진 그들만의 네트워크를 가질 수 있습니다.</span> <span>하지만 집과 다른 지역 사이에, 아주 먼 곳에 케이블을 연결할 수는 없습니다. 이 문제를 어떻게 처리 할 수 있을까요?</span> <span>예를 들어 전력 및 전화와 같이 이미 집에 연결된 케이블이 있습니다.</span> <span>전화기 기반의 시설은 이미 세계 어느 곳과도 연결되어 있으므로 우리가 필요로 하는 완벽한 배선이라고 할 수 있습니다.</span> 따라서 <span>우리의 네트워크를 전화 시설과 연결하기 위해선, 모뎀이라는 특수 장비가 필요합니다.</span> <span>이 모뎀은 우리 네트워크의 정보를 전화 시설에서 처리 할 수있는 정보로 바꾸며, 그 반대의 경우도 마찬가지입니다.</span></span></p> + +<p><img alt="A router linked to a modem" src="https://mdn.mozillademos.org/files/8451/internet-schema-6.png" style="height: 340px; width: 600px;"></p> + +<p><span id="result_box" lang="ko"><span>그래서 우리의 네트워크는 전화 시설에 연결됩니다.</span> <span>다음 단계는 우리의 네트워크에서 도달하려는 네트워크로 메시지를 보내는 것입니다.</span> <span>그렇게하기 위해 네트워크를 인터넷 서비스 제공 업체 (</span></span>Internet Service Provider, <span lang="ko"><span>ISP)에 연결합니다.</span> <span>ISP는 모두 함께 연결되는 몇몇 특수한 라우터를 관리하고 다른 ISP의 라우터에도 액세스 할 수 있는 회사입니다.</span> <span>따라서 우리 네트워크의 메시지는 ISP 네트워크의 네트워크를 통해 대상 네트워크로 전달됩니다.</span> <span>인터넷은 이러한 전체 네트워크 인프라로 구성됩니다.</span></span></p> + +<p><img alt="Full Internet stack" src="https://mdn.mozillademos.org/files/8453/internet-schema-7.png" style="height: 1293px; width: 340px;"></p> + +<h3 id="컴퓨터_찾기">컴퓨터 찾기</h3> + +<p><span id="result_box" lang="ko"><span>컴퓨터에 메시지를 보내려면 메시지를 받을 특정 컴퓨터를 지정해야합니다.</span> <span>따라서 네트워크에 연결된 모든 컴퓨터에는 IP 주소 (IP는 인터넷 프로토콜을 나타냄)라는 고유한 주소가 있습니다.</span> <span>주소는 점으로 구분 된 네 개의 숫자로 구성된 주소입니다 </span></span> . 예: <code>192.168.2.10</code>.</p> + +<p><span id="result_box" lang="ko"><span>컴퓨터는 이러한 주소로 다른 컴퓨터를 찾아가는데 문제가 없습니다. 그러나 우리들은 IP주소를 기억하기 어렵죠.</span> <span>그래서 우리는 '도메인 이름' 이라고하는 사람이 읽을 수 있는 IP 주소의 이름을 지정할 수 있습니다.</span> <span>예를 들어 </span></span><code>'google.com'</code><span lang="ko"><span>은 IP 주소로 </span></span><code>'173.194.121.32'</code><span id="result_box" lang="ko"><span> 입니다. </span><span>따라서 '도메인 이름'은 'IP주소'보다 인터넷을 사용하기에 쉽습니다.</span></span></p> + +<p><img alt="Show how a domain name can alias an IP address" src="https://mdn.mozillademos.org/files/8405/dns-ip.png" style="height: 160px; width: 330px;"></p> + +<h3 id="인터넷과_웹">인터넷과 웹</h3> + +<p><span id="result_box" lang="ko"><span>웹 브라우저를 사용하여 웹을 탐색 할 때 일반적으로 도메인 이름을 사용하여 웹 사이트에 접속합니다.</span> <span>그것은 인터넷과 웹이 같은 것을 의미할까요?</span> <span>그렇게 간단하지 않습니다.</span> <span>앞에서 보았 듯이 인터넷은 수십억 대의 컴퓨터를 모두 연결하는 기술 인프라입니다.</span> 이러한 컴퓨터들 중에 일부는 '웹 서버'로서 <span>웹 브라우저가 이해할 수 있는 서비스를 제공합니다.</span> <span>인터넷은 인프라이며, 웹은 그 인프라 기반 위에 구축된 서비스입니다.</span> 웹 뿐만 아니라 인터넷 위에 구축된 다른 서비스들(이메일, </span>{{Glossary("IRC")}} 등)도 있음을 알아야합니다.</p> + +<h2 id="다음_단계">다음 단계</h2> + +<ul> + <li><a href="/ko/docs/Learn/Getting_started_with_the_web/%EC%9B%B9%EC%9D%98_%EB%8F%99%EC%9E%91_%EB%B0%A9%EC%8B%9D">How the Web works(웹이 작동하는 방법)</a></li> + <li><a href="/en-US/docs/Learn/page_vs_site_vs_server_vs_search_engine">Understanding the difference between a web page, a web site, a web server and a search engine(웹 페이지, 웹 사이트, 웹 서버, 검색 엔진의 차이점 이해하기)</a></li> + <li><a href="/en-US/docs/Learn/Understanding_domain_names">Understanding domain names(도메인 이름 이해하기)</a></li> +</ul> diff --git a/files/ko/learn/common_questions/html_features_for_accessibility/index.html b/files/ko/learn/common_questions/html_features_for_accessibility/index.html new file mode 100644 index 0000000000..fd22e4d8cc --- /dev/null +++ b/files/ko/learn/common_questions/html_features_for_accessibility/index.html @@ -0,0 +1,49 @@ +--- +title: 어떤 HTML 기능이 접근성을 촉진할까? +slug: Learn/Common_questions/HTML_features_for_accessibility +translation_of: Learn/Common_questions/HTML_features_for_accessibility +--- +<p>{{draft}}</p> + +<p class="summary">이번 내용은 웹 페이지를 좀 더 서로 다른 장애를 가진 사람들에게 좀 더 접근하기 쉽게 만들 수 있는 HTML의 특정한 기능을 서술합니다. </p> + +<h2 id="탭(Tabbing)">탭(Tabbing)</h2> + +<p>pointing devices를 사용 하지 않거나 사용 할 수 없는 유저들은 <kbd>Tab</kbd> 을 links를 통해 할 수 있습니다.(links는 논리적 순서로 이루어져 있어야 합니다.) tabindex 속성은 당신이 이러한 순서를 정의 할 수 있도록 허락합니다. 만약 HTML이 선형이라면, 논리적 탭 순서는 자동적으로 맞춰집니다. </p> + +<pre class="brush: html"><ul> + <li><a href="here.html" tabindex="1">Here</a></li> + <li><a href="there.html" tabindex="3">There</a></li> + <li><a href="anywhere.html" tabindex="2">Anywhere</a></li> +</ul></pre> + +<p>이번 예시는(순수히 데모를 위해 사용되었으니 따라하지 마세요), 탭이 여기서부터 여기저기를 점프합니다. </p> + +<h2 id="링크_제목(Link_Titles)">링크 제목(Link Titles)</h2> + +<p>만약 당신이 자신을 설명하지 않는 링크를 가지고 있거나, 링크 목적지가 더 자세하게 설명되지 않으면, 그 링크에 제목 속성을 추가 할 수 있습니다. </p> + +<pre class="brush: html"><p>I'm really bad at writing link text. <a href="inept.html" title="Why I'm rubbish at writing link text: An explanation and an apology.">Click here</a> to find out more.</p></pre> + +<h2 id="접근_키(Access_Keys)">접근 키(Access Keys)</h2> + +<p><em>접근 키는 </em>링크에 사용자가 <kbd>Alt</kbd> or <kbd>Ctrl</kbd> + 접근 키를 입력하여 얻을 수 있는 키보드 단축키를 할당하여 쉬운 네비게이션을 제공합니다. 정확한 키 조합은 플래폼에 따라 다릅니다.</p> + +<pre class="brush: html"><a href="somepage.html" accesskey="s">Some page</a></pre> + +<h2 id="링크_넘어가기(Skip_Links)">링크 넘어가기(Skip Links)</h2> + +<p>탭을 지원하기 위하여, 당신은 유저가 당신의 웹 페이지 모음으로 넘어갈 수 있는 링크를 제공할 수 있습니다. 당신은 아마도 다른 사람이 네비게이션 링크를 따라 점프하기를 원할 것입니다. 그렇게 함으로써, 페이지의 메인 내용을 읽을 수 있습니다. </p> + +<pre class="brush: html"><header> + <h1>The Heading</h1> + <a href="#content">Skip to content</a> +</header> + +<nav> + <!-- navigation stuff --> +</nav> + +<section id="content"> + <!--your content --> +</section></pre> diff --git a/files/ko/learn/common_questions/index.html b/files/ko/learn/common_questions/index.html new file mode 100644 index 0000000000..d3d5fe0261 --- /dev/null +++ b/files/ko/learn/common_questions/index.html @@ -0,0 +1,127 @@ +--- +title: Common questions +slug: Learn/Common_questions +tags: + - CodingScripting + - Infrastructure + - Learn + - NeedsTranslation + - TopicStub + - Web + - WebMechanics + - 웹 + - 인프라 +translation_of: Learn/Common_questions +--- +<p class="summary">This section of the Learning Area is designed to provide answers to common questions that may come up, which are not necessarily part of the structured core learning pathways (e.g. the <a href="/en-US/docs/Learn/HTML">HTML</a> or <a href="/en-US/docs/Learn/CSS">CSS</a> learning articles.) These articles are designed to work on their own.</p> + +<div> +<h2 id="HTML_and_CSS_questions">HTML and CSS questions</h2> + +<p>Try our <a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto">Use HTML to solve common problems</a> and <a href="/en-US/docs/Learn/CSS/Howto">Use CSS to solve common problems</a> pages for common solutions to HTML/CSS problems.</p> +</div> + +<h2 id="웹의_동작_방식">웹의 동작 방식</h2> + +<p>이 섹션에서는 웹의 원리 - 웹의 생태계와 작동 방식에 대한 일반적인 지식과 관련된 질문들을 다룬다.</p> + +<dl> + <dt> + <h3 id="인터넷은_어떻게_동작하는가"><a href="/en-US/docs/Learn/Common_questions/How_does_the_Internet_work">인터넷은 어떻게 동작하는가?</a></h3> + </dt> + <dd><strong>인터넷</strong>은 웹을 가능하게 하는 기술적 기반 구조의 중추이다. 기본적으로, 인터넷은 서로 통신하는 컴퓨터들의 큰 네트워크이다. 이 article은 기초적인 수준에서 인터넷이 어떻게 동작하는지 설명한다.</dd> + <dt> + <h3 id="What_is_the_difference_between_webpage_website_web_server_and_search_engine"><a href="/en-US/docs/Learn/Common_questions/Pages_sites_servers_and_search_engines">What is the difference between webpage, website, web server, and search engine?</a></h3> + </dt> + <dd>In this article we describe various web-related concepts: webpages, websites, web servers, and search engines. These terms are often confused by newcomers to the Web, or are incorrectly used. Let's learn what they each mean!</dd> + <dt> + <h3 id="URL이란"><a href="/en-US/docs/Learn/Common_questions/What_is_a_URL">URL이란?</a></h3> + </dt> + <dd>With {{Glossary("Hypertext")}} and {{Glossary("HTTP")}}, URL is one of the key concepts of the Web. It is the mechanism used by {{Glossary("Browser","browsers")}} to retrieve any published resource on the web.</dd> + <dt> + <h3 id="도메인_네임이란"><a href="/en-US/docs/Learn/Common_questions/What_is_a_domain_name">도메인 네임이란?</a></h3> + </dt> + <dd>Domain names are a key part of the Internet infrastructure. They provide a human-readable address for any web server available on the Internet.</dd> + <dt> + <h3 id="웹서버란"><a href="/en-US/docs/Learn/Common_questions/What_is_a_web_server">웹서버란?</a></h3> + </dt> + <dd>The term "Web server" can refer to the hardware or software that serves web sites to clients across the Web — or both of them working together. In this article we go over how web servers work, and why they're important.</dd> + <dt> + <h3 id="하이퍼링크란"><a href="/en-US/docs/Learn/Common_questions/What_are_hyperlinks">하이퍼링크란?</a></h3> + </dt> + <dd>In this article, we'll go over what hyperlinks are and why they matter.</dd> +</dl> + +<h2 id="Tools_and_setup">Tools and setup</h2> + +<p>Questions related to the tools/software you can use to build websites.</p> + +<dl> + <dt> + <h3 id="How_much_does_it_cost_to_do_something_on_the_Web"><a href="/en-US/docs/Learn/Common_questions/How_much_does_it_cost">How much does it cost to do something on the Web?</a></h3> + </dt> + <dd>When you're launching a website, you may spend nothing or your costs may go through the roof. In this article we discuss how much everything costs and what you get for what you pay (or don't pay).</dd> + <dt> + <h3 id="What_software_do_I_need_to_build_a_website"><a href="/en-US/docs/Learn/Common_questions/What_software_do_I_need">What software do I need to build a website?</a></h3> + </dt> + <dd>In this article we explain which software components you need when you're editing, uploading, or viewing a website.</dd> + <dt> + <h3 id="What_text_editors_are_available"><a href="/en-US/docs/Learn/Common_questions/Available_text_editors">What text editors are available?</a></h3> + </dt> + <dd>In this article we highlight some things to think about when choosing and installing a text editor for web development.</dd> + <dt> + <h3 id="How_do_I_set_up_a_basic_working_environment"><a href="/en-US/docs/Learn/Common_questions/Set_up_a_basic_working_environment">How do I set up a basic working environment?</a></h3> + </dt> + <dd>When working on a web project, you'll want to test it locally before you show it to the world. Some types of code require a server to test, and in this article we'll show you how to set one up. We'll also cover how to put a scalable structure in place so that your files stay organized even when your project gets big.</dd> + <dt> + <h3 id="What_are_browser_developer_tools"><a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">What are browser developer tools?</a></h3> + </dt> + <dd>Every browser features a set of devtools for debugging HTML, CSS, and other web code. This article explains how to use the basic functions of your browser's devtools.</dd> + <dt> + <h3 id="How_do_you_make_sure_your_website_works_properly"><a href="/en-US/docs/Learn/Common_questions/Checking_that_your_web_site_is_working_properly">How do you make sure your website works properly?</a></h3> + </dt> + <dd>So you've published your website online — very good! But are you sure it works properly? This article provides some basic troubleshooting steps.</dd> + <dt> + <h3 id="How_do_you_upload_files_to_a_web_server"><a href="/en-US/docs/Learn/Common_questions/Upload_files_to_a_web_server">How do you upload files to a web server?</a></h3> + </dt> + <dd>This article shows how to publish your site online with <a class="glossaryLink" href="https://developer.mozilla.org/en-US/docs/Glossary/FTP" title="FTP: FTP (File Transfer Protocol) is the standard network protocol for transferring files from one host to another over the Internet through TCP.">FTP</a> tools — one fo the most common ways to get a website online so others can access it from their computers.</dd> + <dt> + <h3 id="How_do_I_use_GitHub_Pages"><a href="/en-US/docs/Learn/Common_questions/Using_GitHub_Pages">How do I use GitHub Pages?</a></h3> + </dt> + <dd>This article provides a basic guide to publishing content using GitHub's gh-pages feature.</dd> + <dt> + <h3 id="How_do_you_host_your_website_on_Google_App_Engine"><a href="/en-US/Learn/Common_questions/How_do_you_host_your_website_on_Google_App_Engine">How do you host your website on Google App Engine?</a></h3> + </dt> + <dd>Looking for a place to host your website? Here's a step-by-step guide to hosting your website on Google App Engine.</dd> + <dt> + <h3 id="What_tools_are_available_to_debug_and_improve_website_performance"><a href="/en-US/docs/Tools/Performance">What tools are available to debug and improve website performance?</a></h3> + </dt> + <dd>This set of articles shows you how to use the Developer Tools in Firefox to debug and improve performance of your website, using the tools to check the memory usage, the JavaScript call tree, the amount of DOM nodes being rendered, and more.</dd> +</dl> + +<h2 id="Design_and_accessibility">Design and accessibility</h2> + +<p>This section lists questions related to aesthetics, page structure, accessibility techniques, etc.</p> + +<dl> + <dt> + <h3 id="How_do_I_start_to_design_my_website"><a href="/en-US/docs/Learn/Common_questions/Thinking_before_coding">How do I start to design my website?</a></h3> + </dt> + <dd>This article covers the all-important first step of every project: define what you want to accomplish with it.</dd> + <dt> + <h3 id="What_do_common_web_layouts_contain"><a href="/en-US/docs/Learn/Common_questions/Common_web_layouts">What do common web layouts contain?</a></h3> + </dt> + <dd>When designing pages for your website, it's good to have an idea of the most common layouts. This article runs thorugh some typical web layouts, looking at the parts that make up each one.</dd> + <dt> + <h3 id="What_is_accessibility"><a href="/en-US/docs/Learn/Common_questions/What_is_accessibility">What is accessibility?</a></h3> + </dt> + <dd>This article introduces the basic concepts behind web accessibility.</dd> + <dt> + <h3 id="How_can_we_design_for_all_types_of_users"><a href="/en-US/docs/Learn/Common_questions/Design_for_all_types_of_users">How can we design for all types of users?</a></h3> + </dt> + <dd>This article provides basic techniques to help you design websites for any kind of user — quick accessibility wins, and other such things.</dd> + <dt> + <h3 id="What_HTML_features_promote_accessibility"><a href="/en-US/docs/Learn/Common_questions/HTML_features_for_accessibility">What HTML features promote accessibility?</a></h3> + </dt> + <dd>This article describes specific features of HTML that can be used to make a web page more accessible to people with different disabilities.</dd> +</dl> diff --git a/files/ko/learn/common_questions/pages_sites_servers_and_search_engines/index.html b/files/ko/learn/common_questions/pages_sites_servers_and_search_engines/index.html new file mode 100644 index 0000000000..a35ea0eedf --- /dev/null +++ b/files/ko/learn/common_questions/pages_sites_servers_and_search_engines/index.html @@ -0,0 +1,125 @@ +--- +title: '웹페이지, 웹사이트, 웹서버 그리고 검색엔진의 차이는 무엇일까요?' +slug: Learn/Common_questions/Pages_sites_servers_and_search_engines +tags: + - 웹동작 + - 웹작동 + - 초보자 +translation_of: Learn/Common_questions/Pages_sites_servers_and_search_engines +--- +<div class="summary"> +<p><span class="seoSummary">이번 글에서는 다양한 웹 관련 개념들을 이야기합니다: 웹, 페이지, 웹사이트, 웹서버, 검색엔진. 이런 용어들은 흔히ㅣ웹을 처음 배우는 사람이나 잘못 배운 사람들에게 혼란스럽습니다. 이것들이 무엇을 의미하는 지 배워봅시다!</span></p> +</div> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">요구지식:</th> + <td><a href="/en-US/Learn/How_the_Internet_works">how the Internet works(인터넷이 작동하는 법)</a>을 배워야 한다.</td> + </tr> + <tr> + <th scope="row">목적:</th> + <td>웹페이지, 웹사이트, 웹서버, 검색엔진의 차이점을 논할 수 있다.</td> + </tr> + </tbody> +</table> + +<h2 id="요약">요약</h2> + +<p>지식의 범위에 따라, 웹은 많은 용어가 있습니다. 걱정마세요, 우리는 그런 모든 것들로 여러분을 억누르지 않을 것입니다. (궁금하시다면, <a href="/en-US/docs/Glossary">glossary(용어사전)</a> 이 있습니다.) 하지만 여러분이 처음에 이해할 필요가 있는 기본적인 용어들이 있습니다. 왜냐하면, 읽는 내내, 이런 표현들을 보게될 것이기 때문이다. 때때로 이런 용어들은 혼동하기 쉽습니다. 왜냐하면 다른 기능을 가지고 있지만 관련있는 것으로 언급되기 때문이죠. 사실, 뉴스 기사 등에서 이따금 잘못 사용된 이런 용어들을 볼 수 있을 것입니다. 그래서 그것들이 혼동되는 것은 당연합니다!</p> + +<p>나아가서 더 자세한 용어와 기술들을 다룰 것입니다. 하지만, 앞서 정의해보는 것은 시작하는 데 도움이 될 것입니다:</p> + +<dl> + <dt>웹 페이지</dt> + <dd>파이어폭스, 구글 크롬, 오페라, MS 익스플로러나 엣지, 애플의 사파리 같은 웹 브라우저에서 보여지는 문서이다. 이런 것들을 단순히 "페이지"라고 하기도 한다.</dd> + <dt>웹사이트</dt> + <dd>다양한 방식으로 그룹으로 묶이거나 연결된 웹 페이지들의 모음이다. 보통 "웹사이트"나 단순히 "사이트"라고 한다.</dd> + <dt>웹 서버</dt> + <dd>인터넷에 웹사이트를 호스팅하는 컴퓨터이다.</dd> + <dt>검색 엔진</dt> + <dd>구글, 빙, 야후 같은 다른 웹 페이지들을 찾게 도와주는 웹사이트이다.</dd> +</dl> + +<p>도서관과 간단한 유사점을 보자. 아래는 도서관에 방문했을 때, 일반적으로 하는 일이다:</p> + +<ol> + <li>검색 색인을 발견하고 원하는 책의 제목을 찾는다.</li> + <li>책의 분류번호를 기록한다.</li> + <li>그 책이 있는 구역으로 간 뒤, 올바른 분류번호를 찾고, 책을 얻는다.</li> +</ol> + +<p>웹 서버와 도서관을 비교해보자.</p> + +<ul> + <li>도서관은 웹 서버와 같다. 도서관은 여러 구역이 있는데, 이것은 다양한 웹사이트들을 호스팅하는 서버와 비슷합니다.</li> + <li>도서관에 있는 과학, 수학, 역사와 같은 각기 다른 구역들은 웹사이트와 같습니다. 각각의 구역은 유일한 웹사이트입니다. (두 개의 구역이 같은 책을 포함하지 않는다.)</li> + <li>구역에 있는 책들은 웹페이지와 같다. 한 웹사이트는 여러 웹페이지들을 가지고 있을 수 있습니다. 예를 들어, 과학 섹션(웹사이트)는 열, 소리, 열역학, 정역학 등의 책(웹페이지)를 가지고 있을 것이다.</li> + <li>검색 색인은 검색 엔진과 같다. 각각의 책은 도서관에서 자신만의 위치를 가지고 있다. (두 개의 책이 같은 위치에 놓일 수 없다.) 이 위치는 분류번호로 정해진다.</li> + <li>비슷하게, 웹페이지는 유일한 주소를 갖습니다. 이런 주소들은 파이폭스, 크롬, 사파리같은 웹 브라우저의 주소창에 주소를 적으면 웹 서버에서 웹페이지를 검색하기 위해 사용됩니다.</li> +</ul> + +<dl> + <dt></dt> +</dl> + +<h2 id="Active_learning">Active learning</h2> + +<p><em>There is no active learning available yet. <a href="https://developer.mozilla.org/en-US/docs/MDN/Getting_started">Please, consider contributing</a>.</em></p> + +<h2 id="깊게_들어가기">깊게 들어가기</h2> + +<p>4개의 용어가 얼마나 관련됐는지, 서로 헷갈리는 이유가 무엇인지를 더 깊게 알아봅시다.</p> + +<h3 id="웹_페이지">웹 페이지</h3> + +<p>웹 페이지는 {{Glossary("browser")}}(브라우저)를 통해 보여지는 단순한 문서입니다. 이런 문서는 {{Glossary("HTML")}} 언어로 쓰여집니다. (<a href="https://developer.mozilla.org/en-US/docs/Web/HTML">다른 글</a>에서 더 자세히 알 수 있다) 웹 페이지는 다양한 다른 종류의 자원을 포함할 수 있습니다:</p> + +<ul> + <li><em>style information(스타일 정보) </em>— 페이지의 외관과 느낌을 관리</li> + <li> + <p><em>scripts(스크립트)</em> — 페이지에 interactivity(대화식 이용)을 첨가</p> + </li> + <li><em>media</em>(미디어) — 사진, 소리, 동영상</li> +</ul> + +<div class="note"> +<p><strong>Note: </strong>브라우저는 또한 {{Glossary("PDF")}} 파일이나 이미지를 보여줄 수 있다. 그러나 <strong>웹 페이지</strong>는 HTML 문서를 의미하는 용어이다. 아니라면 우리는 <strong>문서(document)</strong>라는 용어를 사용한다.</p> +</div> + +<p>웹에서 이용하는 모든 웹 페이지는 유일한 주소를 통해 접근할 수 있습니다. 한 페이지에 접근하기 위해서는, 브라우저의 주소창에 주소를 적으면 됩니다.</p> + +<p style="text-align: center;"><img alt="Example of a web page address in the browser address bar" src="https://mdn.mozillademos.org/files/8529/web-page.jpg" style="height: 239px; width: 650px;"></p> + +<p><em>웹사이트</em> 는 유일한 도메인 이름을 같이 사용하는 연결된 웹 페이지들의 모음입니다. (관련된 자원도 포함된다.) 각각의 웹사이트에서 분명한 링크가 주어진 웹 페이지들은 유저가 그 웹사이트의 한 페이지에서 다른 페이지로 이동하게 합니다. 보통 클릭할 수 있는 형태로 되어있습니다.</p> + +<p>웹사이트에 접근하기 위해서, 브라우저 주소 창에 도메인 이름을 적으면, 브라우저는 웹사이트의 메인 페이지나<em> 홈페이지 </em>(보통 "홈"이라 하는)를 보여줄 것이다:</p> + +<p><img alt="Example of a web site domain name in the browser address bar" src="https://mdn.mozillademos.org/files/8531/web-site.jpg" style="display: block; height: 365px; margin: 0px auto; width: 650px;"></p> + +<p><em>웹 페이지 </em>와 <em>웹사이트 에 대한 생각은</em> 특히 하나의<em>웹 페이지</em>만 포함하는 <em>웹사이트</em>에서 혼동하기 쉽습니다. 이런 웹사이트를 보통 a <em>single-page website(싱글 페이지 웹사이트)</em>라고 합니다.</p> + +<h3 id="웹_서버">웹 서버</h3> + +<h5 id="웹_서버는_한_개_이상의_웹사이트를_호스팅하는_컴퓨터입니다._호스팅은_모든_웹_페이지_및_웹_페이지가_지원하는_파일들을_컴퓨터에서_이용할_수_있다는_것을_의미한다._웹_서버는_유저의_request요청마다_호스팅하는_웹사이트에서_유저의_브라우저로_웹_페이지를_보낼_것이다."><em>웹 서버</em>는 한 개 이상의 <em>웹사이트</em>를 호스팅하는 컴퓨터입니다. "호스팅"은 모든 <em>웹 페이지</em> 및 웹 페이지가 지원하는 파일들을 컴퓨터에서 이용할 수 있다는 것을 의미한다. <em>웹 서버</em>는 유저의 request(요청)마다 호스팅하는 <em>웹사이트</em>에서 유저의 브라우저로 <em>웹 페이지</em>를 보낼 것이다.</h5> + +<p><em>웹 사이트</em>와<em> 웹 서버</em>를 혼동하지 마라. 예를 들어, 당신이 누군가 "내 웹사이트가 반응하지 않는다." 라고 말하는 것을 들었다면, 그것은 사실 <em>웹 서버</em>가 반응하지 않는다는 의미이다. 그러므로 <em>웹사이트</em>를 이용하지 못 한다. 더 중요하게, <em>웹 서버</em>는 여러 웹사이트에 호스팅될 수 있기 때문에, 웹 서버라는 용어는 절대 웹사이트를 지정하기 위해 사용하지 않는다. 그것이 큰 혼란을 일으킬 수 있기 때문이다. 아까의 예처럼, 만약 우리가 "내 웹 서버가 반응하지 않는다." 라고 하면, 그것은 웹 서버가 이용할 수 있는 웹 사이트가 없다는 것을 의미한다.</p> + +<h3 id="검색_엔진">검색 엔진</h3> + +<p>검색 엔진은 웹에서 흔한 혼란의 근원입니다. 검색 엔진은 웹 페이지를 <em>다른</em> 웹사이트에서 찾을 수 있게 도와주는 특별한 종류의 웹사이트입니다.</p> + +<p>검색 엔진은 다음과 같습니다: <a href="https://www.google.com/">Google</a>, <a href="https://www.bing.com/">Bing</a>, <a href="https://www.yandex.com/">Yandex</a>, <a href="https://duckduckgo.com/">DuckDuckGo</a>, 그리고 더 많은 검색 엔진들이 있습니다. 일부는 일반적인 것을 위한 것이고, 일부는 특정한 주제에 특화되어 있습니다. 선호하는 것을 사용하면 됩니다.</p> + +<p>많은 웹 초보자들은 검색 엔진과 브라우저를 혼돈합니다. 분명히 합시다: <em><strong>브라우저</strong></em>는 소프트웨어의 한 조각으로, 웹 페이지를 검색하고 보여줍니다; <em><strong>검색 엔진</strong></em>은 사람들이 다른 웹사이트에서 웹 페이지를 찾도록 도와주는 웹 사이트입니다. 혼란이 생기는 이유는, 처음 브라우저를 실행하면, 브라우저는 검색 엔진의 홈페이지를 보여주기 때문입니다. 이것이 의미있는 이유는 브라우저로 가장 하고 싶은 일이 보여줄 웹 페이지를 찾는 것이기 때문이다. 브라우저같은 기반 시설을 검색엔진 같은 서비스와 혼동하지마세요. 이것을 구별하는 것이 상당히 도움이 될 것입니다. 그러나 몇몇의 전문가들도 느슨하게 말하므로, 염려하지 않아도 됩니다.</p> + +<p>기본 시작 페이지로 구글 검색 상자를 보여주는 파이어폭의 한 예입니다.</p> + +<p><img alt="Example of Firefox nightly displaying a custom Google page as default" src="https://mdn.mozillademos.org/files/8533/search-engine.jpg" style="display: block; height: 399px; margin: 0px auto; width: 650px;"></p> + +<h2 id="다음_단계">다음 단계</h2> + +<ul> + <li>더 깊게 들어가기: <a href="/en-US/docs/Learn/What_is_a_web_server">What is a web server(웹 서버란 무엇인가)</a></li> + <li>웹 페이지들이 웹 사이트로 연결되는 방법 보기: <a href="/en-US/docs/Learn/Understanding_links_on_the_web">Understanding links on the web(웹에서의 연결 이해하기)</a></li> +</ul> diff --git a/files/ko/learn/common_questions/set_up_a_local_testing_server/index.html b/files/ko/learn/common_questions/set_up_a_local_testing_server/index.html new file mode 100644 index 0000000000..5cc1d21caa --- /dev/null +++ b/files/ko/learn/common_questions/set_up_a_local_testing_server/index.html @@ -0,0 +1,112 @@ +--- +title: 로컬 테스트 서버 설치하기 +slug: Learn/Common_questions/set_up_a_local_testing_server +tags: + - Express + - Flask + - Learn + - Node + - PHP + - django + - lamp + - 서버 + - 서버측 + - 초보자 + - 파이썬 +translation_of: Learn/Common_questions/set_up_a_local_testing_server +--- +<div class="summary"> +<p>이 글에서는 간단한 로컬 테스트 서버를 여러분의 장비에 설치하는 법과 기본적인 사용법을 설명합니다.</p> +</div> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">사전 준비:</th> + <td><a href="/en-US/docs/Learn/How_the_Internet_works">인터넷의 작동 방법</a>과 <a href="/en-US/docs/Learn/What_is_a_Web_server">웹서버</a>에 대해 알고 있어야 합니다.</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>로컬 테스트 서버를 설치하는 법을 배울 것입니다.</td> + </tr> + </tbody> +</table> + +<h2 id="로컬_파일과_원격_파일">로컬 파일과 원격 파일</h2> + +<p>대부분의 학습 분야에 걸쳐서 여러분은 그냥 웹브라우저로 예제들을 직접 열어보기만 하면 됩니다. — 브라우저를 통해 예제들을 직접 열어보는 것은 HTML 파일을 더블 클릭하거나 브라우저 창으로 예제들을 드래그 앤 드롭하거나 또는 <em>File</em> > <em>Open...</em> 메뉴에서 해당하는 HTML 파일을 선택하면 됩니다. 이를 수행하는 방법은 많습니다.</p> + +<p>웹 주소 경로가 <code>file://</code>로 시작하고 뒤에 오는 경로가 여러분의 로컬 하드 드라이브에 있는 파일의 경로인 경우, 로컬 파일이 사용되는 것입니다. 이와는 달리, GitHub (또는 다른 원격 서버에 있는) 예제를 보는 경우에는 웹 주소가 <code>http://</code>나 <code>https://</code>로 시작하며, 이는 그 파일이 HTTP를 통해 수신된 파일이라는 것을 나타냅니다.</p> + +<h2 id="로컬_파일로_테스트할_때의_문제점">로컬 파일로 테스트할 때의 문제점</h2> + +<p>일부 예제는 로컬 파일과 같은 방식으로 열면 동작하지 않습니다. 여기에는 여러 가지 원인이 있을 수 있으며, 대부분은 다음과 같습니다:</p> + +<ul> + <li><strong>비동기 요청인 경우</strong>. 일부 브라우저(크롬을 포함하는)에서는 로컬 파일의 예제를 실행할 경우에 비동기 요청(<a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Fetching_data">서버로부터 데이터 가져오기 - Fetching data from the server</a>를 참고)이 작동하지 않을 것입니다. 이는 보안 제한(웹 보안과 관련된 자세한 내용은 <a href="/en-US/docs/Learn/Server-side/First_steps/Website_security">웹사이트 보안- Website security</a>을 참고하세요) 때문입니다.</li> + <li><strong>서버측 언어인 경우</strong>. 서버측 언어(PHP나 Python과 같은)는 코드를 해석하고 결과를 내보낼 수 있는 특별한 서버가 필요합니다.</li> +</ul> + +<h2 id="간단한_로컬_HTTP_서버_실행하기">간단한 로컬 HTTP 서버 실행하기</h2> + +<p>비동기 요청 문제를 해결하려면 로컬 웹 서버에서 예제를 실행하여 테스트해야 합니다. 이를 위한 가장 쉬운 방법은 파이썬(Python)의 <code>SimpleHTTPServer</code> 모듈을 사용하는 것입니다. (설치된 파이썬 버전에 따라 <code>http.server</code> 모듈을 사용해야 할 수도 있습니다.)</p> + +<p>이를 위해:</p> + +<ol> + <li> + <p>파이썬을 설치합니다. 리눅스나 맥OS 사용자라면 이미 시스템에 설치되어 있을 것입니다. 윈도우 사용자일 경우, 다음과 같이 파이썬 홈페이지로부터 설치 프로그램을 다운 받고 설치합니다:</p> + + <ul> + <li>파이썬 홈페이지(<a href="https://www.python.org/">python.org</a>)로 이동합니다.</li> + <li>다운로드(download) 영역에서 Python "3.xxx" 링크를 클릭합니다.</li> + <li>페이지의 아래쪽에 있는 <em>Windows x86 executable installer</em>를 선택하고 다운로드 받습니다.</li> + <li>다운로드가 완료되면 실행합니다.</li> + <li>설치 프로그램의 첫 번째 페이지에서 "Add Python 3.xxx to PATH" 체크박스를 체크해야 합니다.</li> + <li><em>Install</em>을 클릭하고 설치가 완료되면 <em>Close</em>를 클릭합니다.</li> + </ul> + </li> + <li> + <p>명령 실행창(윈도우의 경우는 command prompt, OS/X나 리눅스인 경우에는 터미널창)을 엽니다. 파이썬이 설치되었는지 확인하기 위해 다음 명령을 입력합니다.:</p> + + <pre class="brush: bash notranslate">python -V</pre> + </li> + <li> + <p>이 명령은 버전 번호를 반환합니다. 정상적으로 작동하면, <code>cd</code> 명령을 이용해 여러분의 예제가 존재하는 디렉토리로 이동합니다.</p> + + <pre class="brush: bash notranslate"># 들어가고자 하는 디렉토리 명을 입력합니다. 예를 들어, +cd Desktop +# 한 단계 상위 디렉토리로 이동하려면 점 두 개를 사용합니다. +cd ..</pre> + </li> + <li> + <p>그 경로에 있는 서버를 구동하기 위한 명령을 입력합니다:</p> + + <pre class="brush: bash notranslate"># 위에서 반환된 파이썬 버전이 3.X인 경우 +python -m http.server +# 위에서 반환된 파이썬 버전이 2.X인 경우 +python -m <code>SimpleHTTPServer</code></pre> + </li> + <li> + <p>이 명령은 기본적으로 로컬 웹 서버의 8000번 포트를 이용해 해당 경로의 컨텐츠를 실행시킵니다. 웹 브라우저에서 주소줄에 <code>localhost:8000</code>를 입력하면 이 서버로 이동할 수 있습니다. 그러면 그 디렉토리의 컨텐츠 목록을 볼 수 있는데 실행하고자 하는 HTML 파일을 클릭합니다.</p> + </li> +</ol> + +<div class="note"> +<p><strong>참고</strong>: 8000번 포트에 이미 실행 중인 무언가가 있다면 서버 실행 명령에 다음과 같이 대체 포트 번호를 명시함으로써 다른 포트로 서버를 구동할 수 있습니다.</p> + +<p>예: <code>python -m http.server 7800</code> (Python 3.x일 경우) 또는 <code>python -m SimpleHTTPServer 7800</code> (Python 2.x일 경우). 이 경우, <code>localhost:7800</code>를 통해 서버로 이동할 수 있습니다. </p> +</div> + +<h2 id="서버측_언어를_로컬에서_실행하기">서버측 언어를 로컬에서 실행하기</h2> + +<p>파이썬의 <code>SimpleHTTPServer (python 2.0) http.server (python 3.0)</code> 모듈은 유용하기는 하나 파이썬이나 PHP 또는 자바스크립트와 같은 언어로 작성된 코드를 실행하지 못합니다. 이런 코드를 처리하기 위해서는 뭔가가 더 필요합니다 — 정확하게 무엇이 필요한지는 실행하고자 하는 서버측 언어가 무엇인지에 따라 다릅니다. 다음에 몇 가지 사례를 소개합니다:</p> + +<ul> + <li>파이썬으로된 서버측 코드를 실행하기 위해서는 파이썬 웹 프레임워크(Python web framework)를 사용할 필요가 있습니다. <a href="/en-US/docs/Learn/Server-side/Django">Django Web Framework (Python)</a>를 읽어보면 Django framework를 이용하는 법을 알 수 있습니다. <a href="http://flask.pocoo.org/">Flask</a>는 Djang를 대신할 좋은(조금 더 가벼운) 대안이될 수 있습니다. Flask를 실행하기 위해서는 Python/PIP(<a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/development_environment#Installing_Python_3">install Python/PIP</a>)를 설치하고, <code>pip3 install flask</code> 명령으로 Flask를 설치해야 합니다. 이 때부터 파이썬 Flask 예제를 실행할 수 있는데, 예를 들어, <code>python3 python-example.py</code>명령을 실행하고 브라우저에서 <code>localhost:5000</code>으로 이동하면 됩니다.</li> + <li>Node.js (JavaScript)라는 서버측 코드를 실행하기 위해서는 기본 node(raw node)나 그 위에 설치되는 프레임워크를 이용해야 합니다. Express가 좋은 선택이될 수 있습니다 — <a href="/en-US/docs/Learn/Server-side/Express_Nodejs">Express Web Framework (Node.js/JavaScript)</a>를 살펴보시기 바랍니다.</li> + <li>PHP로된 서버측 코드를 실행하려면 PHP에 내장된 개발서버(<a href="http://php.net/manual/en/features.commandline.webserver.php">PHP's built-in development server</a>)를 실행시킵니다:</li> +</ul> + +<pre class="shellcode notranslate">$ cd path/to/your/php/code +$ php -S localhost:8000</pre> diff --git a/files/ko/learn/common_questions/upload_files_to_a_web_server/index.html b/files/ko/learn/common_questions/upload_files_to_a_web_server/index.html new file mode 100644 index 0000000000..225b587dc7 --- /dev/null +++ b/files/ko/learn/common_questions/upload_files_to_a_web_server/index.html @@ -0,0 +1,134 @@ +--- +title: How do you upload files to a web server? +slug: Learn/Common_questions/Upload_files_to_a_web_server +translation_of: Learn/Common_questions/Upload_files_to_a_web_server +--- +<div class="summary"> +<p>본 글은 어떻게 {{Glossary("FTP")}} 도구를 사용하여 사이트를 발행(publish) 할 수 있는지를 다루고 있습니다.</p> +</div> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">선행조건:</th> + <td> + <p>먼저 웹 서버가 무엇인지(<a href="https://developer.mozilla.org/en-US/Learn/What_is_a_web_server">what a web server is</a>)와 어떤 식으로 도메인이 작동하는지(<a href="https://developer.mozilla.org/en-US/Learn/Understanding_domain_names">how domain names work</a>)를 알아야 합니다. 더불어 어떻게 기본 환경을 구성하는지(<a href="/en-US/Learn/Set_up_a_basic_working_environment">set up a basic environment</a>)와 간단한 웹 페이지 작성법(<a href="/en-US/Learn/HTML/Write_a_simple_page_in_HTML">write a simple webpage</a>)을 알고 있어야 합니다.</p> + </td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>FTP를 이용해 파일들을 서버에 올리기.</td> + </tr> + </tbody> +</table> + +<h2 id="개요">개요</h2> + +<p>당신은 이미 간단한 웹 페이지를 만들었습니다.(<a href="/en-US/Learn/HTML/Write_a_simple_page_in_HTML">you have built a simple page</a> 참조), 이제 웹 서버에 올려 온라인에 공개하고 싶을 겁니다. 우리는 이러한 방법을 {{Glossary("FTP")}}를 통해 다뤄보고자 합니다.</p> + +<h2 id="따라해보기">따라해보기</h2> + +<p><em>아직 좋은 예제가 없습니다. 누군가 나서 주세요(<a href="/en-US/docs/MDN/Getting_started">Please, consider contributing</a>).</em></p> + +<h2 id="깊이_파보기">깊이 파보기</h2> + +<h3 id="FTP_클라이언트와_함께_해보기_FireFTP">FTP 클라이언트와 함께 해보기: FireFTP</h3> + +<p>세상에는 다양한 종류의 FTP 클라이언트들이 있습니다. 본 문서에서는 FireFTP를 다룰 겁니다. FireFTP는 파이어 폭스에서 다루기 쉽습니다. 만약 파이어폭스를 사용하신다면 FireFTP 애드온 페이지(<a href="https://addons.mozilla.org/firefox/addon/fireftp/">FireFTP's addons page</a>) 에 가셔서l FireFTP를 설치하시면 됩니다.</p> + +<div class="note"> +<p>물론 FireFTP 외에도 수 많은 대안이 있습니다. 관심이 있다면 퍼블리싱 도구: FTP 클라이언트(<a href="/en-US/Learn/How_much_does_it_cost#Publishing_tools.3A_FTP_client">Publishing tools: FTP clients</a>) 항목을 참조하시면 되겠습니다.</p> +</div> + +<p>FireFTP를 새로운 탭에서 열어보세요. 파이어폭스에서 열기 위한 방법도 두가지 있습니다.</p> + +<ol> + <li><strong>Firefox menu <img alt="" src="https://mdn.mozillademos.org/files/9633/2014-01-10-13-08-08-f52b8c.png" style="height: 16px; width: 16px;"> ➤ <img alt="Developer" src="https://mdn.mozillademos.org/files/9635/Screenshot%20from%202014-11-26%2014:24:56.png" style="height: 24px; vertical-align: middle; width: 27px;"> ➤ FireFTP</strong></li> + <li><strong>Tools </strong>➤ <strong>Web Develope</strong>r ➤ <strong>FireFTP</strong></li> +</ol> + +<p>이제 다음과 같이 보이게 될겁니다.</p> + +<p><img alt="FireFTP : the interface, not connected to a server" src="https://mdn.mozillademos.org/files/9613/fireftp-default.png" style="height: 800px; width: 1280px;"></p> + +<h3 id="로그인_하기">로그인 하기</h3> + +<p>이 예시에서 우리는 호스팅 제공자가 "Example Hosting Provider"라는 가상의 회사라고 가정합니다. 이 회사의 URLs는 다음과 같습니다 : <code>mypersonalwebsite.examplehostingprovider.net</code>.</p> + +<p>우리는 방금 계정을 만들었고 호스팅제공자로부터 아래와 같은 계정정보를 받았습니다.</p> + +<blockquote> +<p>Congratulations for opening an account at Example Hosting Provider.</p> + +<p>Your account is: <code>demozilla</code></p> + +<p>Your website will be visible at <code>demozilla.examplehostingprovider.net</code></p> + +<p>To publish to this account, please connect through FTP with the following credentials:</p> + +<ul> + <li>FTP server: <code>ftp://demozilla.examplehostingprovider.net</code></li> + <li>User: <code>demozilla</code></li> + <li>Password: <code>quickbrownfox</code></li> + <li>To publish on the web, put your files into the <code>Public/htdocs</code> directory.</li> +</ul> +</blockquote> + +<p>먼저 이곳을 봅시다. <code>http://demozilla.examplehostingprovider.net/</code> — 보시다시피 아직 아무런 정보도 없습니다.</p> + +<p><img alt="Our demozilla personal website, seen in a browser: it's empty" src="https://mdn.mozillademos.org/files/9615/demozilla-empty.png" style="height: 233px; width: 409px;"></p> + +<div class="note"> +<p><strong>Note:</strong> 보이는 화면은 여러분의 호스팅 제공자에 따라 다릅니다. 대부분은 “This website is hosted by [Hosting Service].”과 같은 페이지를 보게될 것입니다.</p> +</div> + +<p>이제 우리의 FTP 클라이언트를 멀리 떨어진 서버에 접속하기 위해 <em>"Create an account..." 버튼을 누릅니다. </em>그리고 호스팅제공자로 부터 받은 정보를 해당 필드에 채워줍니다.</p> + +<p><img alt="FireFTP: creating an account" src="https://mdn.mozillademos.org/files/9617/fireftp-createlogin.png" style="height: 436px; width: 578px;"></p> + +<h3 id="이곳과_저곳_로컬_과_원격_화면">이곳과 "저곳" : 로컬 과 원격 화면</h3> + +<p>이제 새로 만든 계정으로 접속을 해봅시다.</p> + +<p><img alt="The FTP interface, once logged" src="https://mdn.mozillademos.org/files/9619/fireftp-logged.png" style="height: 800px; width: 1280px;"></p> + +<p>어떤 것이 보이는지 조사해봅시다.</p> + +<ul> + <li>왼쪽에는, 여러분 컴퓨터의 로컬파일들이 보입니다. 여러분이 올리고 싶은 파일들이 있는 디렉토리로 이동합시다. (여기에서는 <code>mdn</code>폴더입니다)</li> + <li>오른쪽에는, 원격 파일이 보입니다. 우리는 멀리 떨어진 FTP서버의 디렉토리에 들어온 것입니다. (in this case, <code>users/demozilla</code>)</li> + <li>아래부분은 지금은 무시하셔도 좋습니다. 이 부분은 여러분의 FTP클라이언트와 서버사이의 상호작용(업로드, 다운로드)을 기록해 놓은 곳입니다.</li> +</ul> + +<h3 id="서버에_업로딩">서버에 업로딩</h3> + +<p>여러분이 기억하듯이, 우리의 호스팅제공자는 우리에게 <code>Public/htdocs</code> 디렉토리에 파일을 저장해야한다고 했습니다. 오른쪽 패널에서 해당 디렉토리로 이동해봅시다.</p> + +<p><img alt="Changing to the htdocs folder on the remote server" src="https://mdn.mozillademos.org/files/9623/remote-htdocs-empty.png" style="height: 315px; width: 561px;"></p> + +<p>이제, 여러분의 파일을 서버에 업로드하기 위해서 드래그-앤-드롭하여 파일들을 왼쪽에서 오른쪽 패널로 이동합니다.</p> + +<p><img alt="The files show in the remote view: they have been pushed to the server" src="https://mdn.mozillademos.org/files/9625/files-dropped-onto-the-server.png" style="height: 800px; width: 1280px;"></p> + +<h3 id="우리가_올린_것이_진짜로_온라인으로_되어있나요">우리가 올린 것이 진짜로 온라인으로 되어있나요?</h3> + +<p>지금까지는 좋습니다. 하지만 여러분의 브라우저에서 <code>http://demozilla.examplehostingprovider.net/</code> 주소로 이동하여 재확인 해봅시다.</p> + +<p><img alt="Here we go: our website is live!" src="https://mdn.mozillademos.org/files/9627/here-we-go.png" style="height: 442px; width: 400px;"></p> + +<p>맙소사! 우리의 웹사이트가 잘 올라와있습니다!</p> + +<h3 id="파일_업로드를_위한_다른_방법들">파일 업로드를 위한 다른 방법들</h3> + +<p>FTP 프로토콜은 웹사이트를 출시하기 위해 잘 알려진 방법입니다. 하지만 유일한 방법은 아닙니다. 여기 몇개의 다른 방법들도 있습니다.</p> + +<ul> + <li><strong>Web interfaces</strong>. An HTML interface acting as front-end for a remote file upload service. Provided by your hosting service. 여러분의 호스팅제공자는 HTML 인터페이스로 된(브라우저에서 업로드 가능한) 원격 파일 업로드 서비스를 지원해줄 수도 있습니다.</li> + <li><strong>GitHub</strong> (advanced). {{Glossary("git")}}을 이용해 commit/push 와 같은 방법으로 업로드할 수도 있습니다. <a href="/en-US/Learn/Getting_started_with_the_web">Getting started with the Web</a> 가이드에서 <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Publishing_your_website">Publishing your website</a> 를 읽어보세요.</li> + <li><strong>{{Glossary("Rsync")}}</strong> (advanced). 로컬과 원격의 파일을 동기화하는 방법입니다.</li> + <li><strong>{{Glossary("WebDAV")}}</strong>. An extension of the {{Glossary("HTTP")}} 프로토콜의 확장으로 보다 나은 파일 관리를 가능하게 해주는 확장입니다.</li> +</ul> + +<h2 id="다음_단계">다음 단계</h2> + +<p>잘하셨습니다. 이제 거의 끝났습니다. 마지막으로 중요한 일은 <a href="/en-US/docs/Learn/Checking_that_your_web_site_is_working_properly">make sure your web site is working properly</a> 입니다.</p> diff --git a/files/ko/learn/common_questions/what_are_hyperlinks/index.html b/files/ko/learn/common_questions/what_are_hyperlinks/index.html new file mode 100644 index 0000000000..e036903bd6 --- /dev/null +++ b/files/ko/learn/common_questions/what_are_hyperlinks/index.html @@ -0,0 +1,91 @@ +--- +title: What are hyperlinks? +slug: Learn/Common_questions/What_are_hyperlinks +translation_of: Learn/Common_questions/What_are_hyperlinks +--- +<div class="summary"> +<p>이 글에서, 우리는 하이퍼링크가 무엇이고 왜 중요한지를 살필 것이다.</p> +</div> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">선수지식:</th> + <td><a href="/en-US/Learn/How_the_Internet_works">인터넷이 작동하는 법</a>을 알아야 하고 <a href="/en-US/docs/Learn/page_vs_site_vs_server_vs_search_engine">웹 페이지, 웹사이트, 웹 서버 그리고 검색엔진의 차이</a>에 익숙해야 한다.</td> + </tr> + <tr> + <th scope="row">목적:</th> + <td>하이퍼링크가 무엇이고 왜 중요한지를 배울 것이다.</td> + </tr> + </tbody> +</table> + +<h2 id="요약">요약</h2> + +<p>보통 링크라고 불리는 하이퍼링크는 웹에서 기본적인 개념이다. 링크가 무엇인 지 설명하기 위해, 웹의 매우 기본적인 구조로 돌아볼 필요가 있다.</p> + +<p>1989년으로 돌아가, 웹의 발명가인 Tim Berners-Lee는 웹을 대표하는 3가지 축에 대해 말하였다. :</p> + +<ol> + <li>{{Glossary("URL")}}, 웹 문서를 추적하는 주소 시스템</li> + <li>{{Glossary("HTTP")}}, URL들이 주어졌을 때, 문서들을 찾는 전송 프로토콜</li> + <li>{{Glossary("HTML")}}, 내장된 <em>hyperlinks </em>를 허용하는 문서 형식</li> +</ol> + +<p>3가지 축에서 본 것처럼, 웹에 대한 모든 것들은 문서들과 어떻게 문서에 접근할 것인 지에 관련되어 있다. 웹의 기본 목적은 텍스트 문서를 통해서 도달하고, 읽고, 찾기쉬운 방식을 제공하는 것이다. 그리고 나서, 웹은 이미지와 동영상, 이진 데이터에 접근하는 것을 제공하도록 진화했다. 그러나, 이런 발전은 3가지 축은 거의 바꾸지 못 하였다.</p> + +<p>웹 이전에는, 문서에 접근하고 문서끼리 이동하는 것은 꽤 어려웠다. 인간이 읽을 수 있는 URL은 이런 것들을 훨씬 쉽게 만들었다. 하지만, 문서에 접근할 때마다 긴 URL을 타이핑하는 것은 어려웠다. 이것이 하이퍼링크가 개혁한 모든 것이다. 링크는 URL을 가진 텍스트와 연결될 수 있다. 그렇게 된 링크를 활성화함으로써, 타겟 문서에 즉시 도달할 수 있다.</p> + +<p>기본적으로 파란색으로 밑줄이 된 링크는 주위 텍스트에서 보여진다. 활성화하기 위해 링크를 클릭하거나 Tab키로 링크를 선택하고 Enter키나 Space바를 누르면 된다.</p> + +<p><img alt="Example of a basic display and effect of a link in a web page" src="https://mdn.mozillademos.org/files/8625/link-1.png" style="height: 492px; width: 477px;"></p> + +<p>링크는 웹을 유용하고 성공적으로 만든 돌파구이다. 이 글의 나머지엔, 다양한 유형의 링크와 현대 웹 디자인의 중요성을 얘기할 것이다.</p> + +<h2 id="깊게_들어가기">깊게 들어가기</h2> + +<p>다시 말하면, 링크는 URL이 연결된 텍스트이다. 그리고, 링크를 사용하면, 하나의 문서에서 다른 문서로 쉽게 이동할 수 있다. 이런 내용들을 말하다보면, 몇몇의 생각해볼 뉘앙스차이가 있다.</p> + +<h3 id="링크의_유형들">링크의 유형들</h3> + +<dl> + <dt>Internal link(내부 링크)</dt> + <dd>당신의 웹사이트에 속하는 두 개의 웹사이트 사이의 링크는 내부 링크라고 불린다. 내부 링크가 없다면, 웹 사이트와 같은 것은 없을 것이다. (물론, 한 페이지의 웹 사이트 빼고).</dd> + <dt>External link(외부 링크)</dt> + <dd>당신의 웹사이트에서 다른 사람의 웹사이트로 가는 링크이다. 외부 링크가 없다면, 웹이 존재하지 않는다. 왜냐하면 웹은 웹페이지들의 네트워크이기 때문이다. 당신이 유지하는 내용 외의 정보를 제공하기위해 외부 링크를 사용해라.</dd> + <dt>Incoming links(들어오는 링크)</dt> + <dd>다른 사람의 웹 사이트에서 당신의 사이트로 가는 링크이다. 단지 외부링크의 반대이다. 누군가 당신의 사이트로 링크를 걸 때 당신이 역으로 링크를 걸 필요하는 없다는 것을 기록해라.</dd> +</dl> + +<p>당신이 웹사이트를 구축할 때, 내부링크에 집중해야 한다. 왜냐하면 내부링크가 당신의 사이트를 사용가능하게 해주기 때문이다. 링크가 너무 많거나 너무 적지 않게 좋은 밸런스를 찾아야 한다. 우리는 다른 글에서 웹 사이트 네비게이션을 디자인하는 것에 대해 이야기 할 것이다. 그러나 룰로써, 당신이 새 웹페이지를 추가할 때마다, 적어도 당신의 1개 이상의 페이지에는 새 페이지에 대한 링크를 걸어야 한다. 반면에, 만약 당신의 사이트가 10페이지 이상이라면, 모든 페이지에 링크를 거는 것은 역효과이다.</p> + +<p>당신이 처음 시작할 때, 외부와 들어오는 링크를 많이 걱정할 필요가 없다. 그러나, 그것들은 검색 엔진에서 당신의 사이트를 찾을 때, 매우 중요하다. (자세한 사항은 밑에 있다.)</p> + +<h3 id="Anchors(앵커)">Anchors(앵커)</h3> + +<p>대부분의 링크는 두 개의 웹사이트를 연결한다. <strong>앵커</strong>는한 문서에서 다른 부분들을 연결한다. 앵커가 가리키는 링크를 따라가면, 브라우저는 새 문서를 불러오는 것 대신에 현재 문서의 다른 부분으로 이동한다. 그러나 다른 링크과 같은 방식으로 만들고 사용한다.</p> + +<p><img alt="Example of a basic display and effect of an anchor in a web page" src="https://mdn.mozillademos.org/files/8627/link-2.png" style="height: 492px; width: 477px;"></p> + +<h3 id="링크와_검색엔진">링크와 검색엔진</h3> + +<p>링크는 유저와 검색엔진 모두에게 중요하다. 검색 엔진이 웹페이지를 크롤링할 때마다, 검색엔진은 웹 페이지에서 이용가능한 링크를 따라가면서 웹 사이트를 인덱싱한다. 검색 엔진이 웹 사이트의 다양한 페이지를 발견하기 위해 링크를 따라가는 것뿐만 아니라 타켓 웹페이지에 도달하기 위해 어떤 검색 쿼리가 적절한 지를 결정하기 위해 링크의 텍스트를 사용한다.</p> + +<p>그래서 링크는 얼마나 쉽게 검색 엔진이 너의 사이트를 찾는 지에 영향을 미친다. 문제는 검색 엔진의 활동을 측정하는 것은 어렵다. 회사들은 그들의 사이트가 검색 결과에 높은 랭크가 되기를 자연스럽게 원한다. 그리고, 모든 연구 결과는 적어도 몇몇은 분명하게 해준다.</p> + +<ul> + <li>링크의 <em>텍스트</em>는 어떤 컴색 쿼리들이 주어진 URL을 찾는 지에 영향을 미친다.</li> + <li>웹 페이지가 더 많은 <em>들어오는 링크</em>를 자랑할 수 있다면, 검색 결과 랭킹은 더 높이진다.</li> + <li><em>외부 링크</em>는 소스 웹페이와 타겟 웹페이지의 검색 랭킹에 영향을 미친다. 그러나 얼마나 많은 지는 분명치 않다.</li> +</ul> + +<p><a href="http://en.wikipedia.org/wiki/Search_engine_optimization">SEO</a> (search engine optimization, 검색 엔진 최적화)는 검색 결과에 웹페이지 랭크를 높게 만드는 법에 대한 연구이다. 웹페이지의 링크 사용을 증가시키는 것이 유용한 SEO 기법이다.</p> + +<h2 id="다음_단계">다음 단계</h2> + +<p>그래서 이젠, 당신은 링크가 있는 웹페이지들을 설정하고 싶을 것이다!</p> + +<ul> + <li>더 많은 이론적인 배경을 배우기 위해, <a href="/en-US/docs/Learn/Common_questions/What_is_a_URL">URLs 과 구조</a>를 배울 것이다. 왜냐하면 모든 링크는 URL을 가리키기 때문이다.</li> + <li>좀 더 실용적인 것을 원하나요? <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">HTML 도입</a> 중 <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Creating_hyperlinks">하이퍼 링크 만들기</a> 모듈은 링크를 구현하는 법에 대한 상세한 내용을 설명한다.</li> +</ul> diff --git a/files/ko/learn/common_questions/what_is_a_domain_name/index.html b/files/ko/learn/common_questions/what_is_a_domain_name/index.html new file mode 100644 index 0000000000..8fecee0342 --- /dev/null +++ b/files/ko/learn/common_questions/what_is_a_domain_name/index.html @@ -0,0 +1,149 @@ +--- +title: What is a domain name? +slug: Learn/Common_questions/What_is_a_domain_name +translation_of: Learn/Common_questions/What_is_a_domain_name +--- +<div class="summary"> +<p>이 글에서 domain name(도메인명)에 대해 다룹니다. : 도메인이 무엇인 지, 어떻게 구성되어있는지, 도메인을 어떻게 얻을 수 있는지.</p> +</div> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">선행사항:</th> + <td>우선, <a href="/en-US/docs/Learn/How_the_Internet_works">인터넷이 작동하는 법</a>을 알 필요가 있고, <a href="/en-US/Learn/Understanding_URLs">무엇이 URLs 인 지 이해할 필요가 있다.</a>.</td> + </tr> + <tr> + <th scope="row">목적:</th> + <td>도메인 이름이 무엇인 지에 배우고 그것들이 어떻게 작동하고 왜 중요한 지에 대해 배운다.</td> + </tr> + </tbody> +</table> + +<h2 id="요약">요약</h2> + +<p><span class="seoSummary">도메인 이름은 인터넷 인프라의 핵심 부분입니다. 인터넷에서 사용할 수있는 모든 웹 서버에 대해 사람이 읽을 수있는 주소를 제공합니다.</span></p> + +<p>Any Internet-connected computer can be reached through a public {{Glossary("IP")}} Address, which consists of 32 bits for IPv4 (they are usually written as four numbers between 0 and 255, separated by dots (e.g., <code>173.194.121.32</code>) or which consists of 128 bits for IPv6 (they are usually written as eight groups of 4 hexadecimal numbers, separated by colons (e.g., <code>2027:0da8:8b73:0000:0000:8a2e:0370:1337</code>). Computers can handle those addresses easily, but people have a hard time finding out who's running the server or what service the website offers. IP addresses are hard to remember and might change over time. To solve all those problems we use human-readable addresses called domain names.</p> + +<h2 id="Active_Learning">Active Learning</h2> + +<p><em>아직 이용가능한 Active Learning이 없습니다. <a href="/en-US/docs/MDN/Getting_started">Please, consider contributing</a>.</em></p> + +<h2 id="Deeper_dive">Deeper dive</h2> + +<h3 id="Domain_name의_구조">Domain name의 구조</h3> + +<p>도메인 이름은 몇개의 파트로 이루어진 간단한 구조를 이루고 있습니다. 점으로 구분하고 오른쪽에서 왼쪽으로 읽습니다.</p> + +<p><img alt="Anatomy of the MDN domain name" src="https://mdn.mozillademos.org/files/11229/structure.png" style="height: 76px; width: 252px;"></p> + +<p>각각의 파트들은 전체 도메인 이름에 대해 특별한 정보를 제공합니다. </p> + +<dl> + <dt>{{Glossary("TLD")}} (Top-Level Domain; 최고레벨 도메인).</dt> + <dd>TLD은 가장 일반적인 정보를 제공합니다. TLDs tell users the general purpose of the service behind the domain name. The most generic TLDs (.com, .org, .net) don't require web services to meet strict criteria, but some TLDs enforce stricter policies. For example, local TLDs such as .us, .fr, or .sh can require the service to be provided in a given language or hosted in a certain country.</dd> + <dt>Label (or component)</dt> + <dd>The labels are what follow the TLD. A label can be anything, from one letter to a full sentence. The label located right before the TLD can also be referred as a <em>Secondary Level Domain</em> (SLD). A domain name can have many labels (or components), it is not mandatory nor necessary to have 3 labels to form a domain name. For instance, www.inf.ed.ac.uk is a correct domain name. When controlling the "upper" part of a domain name (e.g. <a href="https://mozilla.org">mozilla.org</a>), one can create other domain names (sometimes called "subdomains") (e.g. <a href="https://developer.mozilla.org">developer.mozilla.org</a>).</dd> +</dl> + +<h3 id="Domain_name_구매하기">Domain name 구매하기</h3> + +<h4 id="누가_도메인_이름을_갖고_있나요">누가 도메인 이름을 갖고 있나요?</h4> + +<p>You cannot “buy a domain name”. You pay for the right to use a domain name for one or more years. You can renew your right, and your renewal has priority over other people's applications. But you never own the domain name.</p> + +<p>Companies called registrars use domain name registries to keep track of technical and administrative information connecting you to your domain name.</p> + +<div class="note"> +<p><strong>Note : </strong>For some domain name, it might not be a registrar which is in charge of keeping track. For instance, every domain name under .fire is managed by Amazon.</p> +</div> + +<h4 id="이용가능한_Domain_Name_찾기">이용가능한 Domain Name 찾기</h4> + +<p>To find out whether a given domain name is available,</p> + +<ul> + <li>Go to a domain name registrar's website. Most of them provide a “whois” service that tells you whether a domain name is available.</li> + <li>Alternatively, if you use a system with a built-in shell, type a <code>whois</code> command into it, as shown here for <code>mozilla.org</code>:</li> +</ul> + +<pre>$ whois mozilla.org +Domain Name:MOZILLA.ORG +Domain ID: D1409563-LROR +Creation Date: 1998-01-24T05:00:00Z +Updated Date: 2013-12-08T01:16:57Z +Registry Expiry Date: 2015-01-23T05:00:00Z +Sponsoring Registrar:MarkMonitor Inc. (R37-LROR) +Sponsoring Registrar IANA ID: 292 +WHOIS Server: +Referral URL: +Domain Status: clientDeleteProhibited +Domain Status: clientTransferProhibited +Domain Status: clientUpdateProhibited +Registrant ID:mmr-33684 +Registrant Name:DNS Admin +Registrant Organization:Mozilla Foundation +Registrant Street: 650 Castro St Ste 300 +Registrant City:Mountain View +Registrant State/Province:CA +Registrant Postal Code:94041 +Registrant Country:US +Registrant Phone:+1.6509030800 +</pre> + +<p>보시는 바와 같이 <code>mozilla.org</code>는 Mozilla Foundation에 의해 이미 등록되어 있기 때문에 등록이 안되네요.</p> + +<p><code>afunkydomainname.org</code>을 등록하는 것도 봅시다</p> + +<pre>$ whois afunkydomainname.org +NOT FOUND +</pre> + +<p>위에 나온 것 같이 도메인이 <code>whois</code> 데이터베이스에 존재하지 않네요. 따라서 이건 등록할수 있습니다. 좋은 정보네요.</p> + +<h4 id="도메인_네임_얻기">도메인 네임 얻기</h4> + +<p>과정은 다음과 같습니다.</p> + +<ol> + <li>등록 웹사이트로 가세요.</li> + <li>일반적으로 눈에 ㄸㅟ게 “Get a domain name” 이라는 글자가 있을거에요. 클릭하세요.</li> + <li>요구하는 상세 정보를 채우세요. 그리고 특별히 원하는 도메인 네임의 스펠링을 정확하게 입력했는지 다시한번 확인해주세요. 한번 지불하면 돌이킬 수 없습니다.</li> + <li>등록이 잘 되었다면 등록 웹사이트에서 연락이 올 것입니다. 그리고 몇시간내로 모든 DNS 서버들이 당신의 DNS 정보를 받을거구요.</li> +</ol> + +<div class="note"> +<p><strong>Note:</strong> In this process the registrar asks you for your real-world address. Make sure you fill it properly, since in some countries registrars may be forced to close the domain if they cannot provide a valid address.</p> +</div> + +<h4 id="DNS_갱신">DNS 갱신</h4> + +<p>DNS databases are stored on every DNS server worldwide, and all these servers refer to a few ones called “authoritative name server” or “top-level DNS servers.” Whenever your registrar creates or updates any information for a given domain, the information must be refreshed in every DNS database. Each DNS server that knows about a given domain stores the information for some time before it is automatically invalidated and then refreshed (the DNS server queries an authoritative server again). Thus, it takes some time for DNS servers that know about this domain name to get the up-to-date information.</p> + +<div class="note"> +<p><strong>Note :</strong> This time is often called <strong>propagation time</strong>. However this term is not precise since the update is not propagating itself (top → down). DNS servers queried by your computer (down) are the ones that fetch the information from the authoritative server (top) when they need it.</p> +</div> + +<h3 id="DNS_리퀘스트는_어떻게_작동할까요">DNS 리퀘스트는 어떻게 작동할까요?</h3> + +<p>As we already saw, when you want to display a webpage in your browser it's easier to type a domain name than an IP address. Let's take a look at the process:</p> + +<ol> + <li>Type <code>mozilla.org</code> in your browser's location bar.</li> + <li>Your browser asks your computer if it already recognizes the IP address identified by this domain name (using a local DNS cache). If it does, the name is translated to the IP address and the browser negotiates contents with the web server. End of story.</li> + <li>If your computer does not know which IP is behind the <code>mozilla.org</code> name, it goes on to ask a DNS server, whose job is precisely to tell your computer which IP address matches each registered domain name.</li> + <li>Now that the computer knows the requested IP address, your browser can negotiate contents with the web server.</li> +</ol> + +<p><img alt="Explanation of the steps needed to obtain the result to a DNS request" src="https://mdn.mozillademos.org/files/8961/2014-10-dns-request2.png" style="height: 702px; width: 544px;"></p> + +<h2 id="다음_단계">다음 단계</h2> + +<p>지금까지 많은 프로세스와 architecture에 대해 이야기 했으니 이제 다음으로 넘어갈 시간이네요.</p> + +<ul> + <li>If you want to get hands-on, it's a good time to start digging into design and explore <a href="/en-US/Learn/Anatomy_of_a_web_page">the anatomy of a web page</a>.</li> + <li>It's also worth noting that some aspects of building a website cost money. Please refer to <a href="/en-US/docs/Learn/How_much_does_it_cost">how much it costs to build a web site</a>.</li> + <li>Or read more about <a href="http://en.wikipedia.org/wiki/Domain_name">Domain Name</a> on Wikipedia.</li> +</ul> diff --git a/files/ko/learn/common_questions/what_is_a_url/index.html b/files/ko/learn/common_questions/what_is_a_url/index.html new file mode 100644 index 0000000000..cc203af11b --- /dev/null +++ b/files/ko/learn/common_questions/what_is_a_url/index.html @@ -0,0 +1,158 @@ +--- +title: What is a URL? +slug: Learn/Common_questions/What_is_a_URL +tags: + - URL + - urls + - 자원 + - 초급자 + - 초보자 +translation_of: Learn/Common_questions/What_is_a_URL +--- +<div class="summary"> +<p>이 글은 Uniform Resource Locators (URLs) 를 설명한다. 또한, URL이 무엇이고 어떻게 구성되어 있는 지도 설명한다.</p> +</div> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">선수지식:</th> + <td><a href="/en-US/docs/Learn/How_the_Internet_works">인터넷이 작동하는 법</a>, <a href="/en-US/docs/Learn/What_is_a_Web_server">웹서버가 무엇인가</a> 그리고 <a href="/en-US/docs/Learn/Understanding_links_on_the_web">웹상의 링크 속에 있는 개념</a>에 대해 먼저 알아야 한다.</td> + </tr> + <tr> + <th scope="row">목적:</th> + <td>URL을 배울 것이고, 웹에서 어떻게 URL이 작동하는 지 배운다.</td> + </tr> + </tbody> +</table> + +<h2 id="요약">요약</h2> + +<p><span class="seoSummary">{{Glossary("Hypertext")}} 와 {{Glossary("HTTP")}} 함께, <strong><dfn>URL</dfn></strong> 은 웹에서 중요한 개념 중 하나이다. URL은 웹에 게시된 어떤 자원을 찾기 위해서 {{Glossary("Browser","browsers")}}에 의해 사용되는 메카니즘이다 .</span></p> + +<p><strong>URL</strong> 은 <em>Uniform Resource Locator</em>(인터넷에서 자원 위치)을 나타낸다. URL은 웹에서 정해진 유일한 자원의 주소일 뿐이다. 이론적으로, 각각의 유일한 URL은 유일한 자원을 가리킨다. 그런 자원은 HTML 페이지, CSS 문서, 이미지 등이 될 수 있다. 실제로, 여러 예외가 있는데, 가장 흔한 URL은 더 이상 존재하지 않는 자원이나 옮겨진 자원을 가리키는 것이다. URL에 의해 표현된 자원과 URL 자체는 웹서버에 의해 다루어지기 때문에, 자원과 관련 URL을 주의 깊게 관리하기 위해서 웹서버의 소유자에게 달려있다..</p> + +<h2 id="Active_Learning(능동_학습)">Active Learning(능동 학습)</h2> + +<p><em>아직 이용 가능한 능동학습이 없습니다. <a href="/en-US/docs/MDN/Getting_started">Please, consider contributing</a>.</em></p> + +<h2 id="깊게_들어가기">깊게 들어가기</h2> + +<h3 id="기본_URL의_구조">기본: URL의 구조</h3> + +<p>여기에 URL의 예제들이 있습니다:</p> + +<pre>https://developer.mozilla.org +https://developer.mozilla.org/en-US/docs/Learn/ +https://developer.mozilla.org/en-US/search?q=URL</pre> + +<p>관련 페이지를 불러오기 위해서, 저 URL들 중 어떤 것이든 주소 창에 적을 수 있습니다. (자원).</p> + +<p>URL 은 다른 파트들과, 몇몇의 의무와 선택사항들로 구성됩니다. 다음 URL을 사용하여 가장 중요한 부분을 봅시다:</p> + +<pre>http://www.example.com:80/path/to/myfile.html?key1=value1&key2=value2#SomewhereInTheDocument</pre> + +<dl> + <dt><img alt="Protocol" src="https://mdn.mozillademos.org/files/15766/mdn-url-protocol@x2_update.png" style="height: 70px; width: 440px;"></dt> + <dd><code>http</code> 는 프로토콜(규약)입니다. URL의 첫 파트는 브라우저가 어떤 규약을 사용해야 하는 지를 나타냅니다. 프로토콜은 컴퓨터 네트워크에서 데이터를 교환하거나 전송하기 위한 방법들의 세트입니다. 보통 웹사이트들을 위해, 이것은 HTTP 프로토콜이나 HTTP 프로토콜의 보안 버전입니다. 웹은 이 두 가지 중 하나를 요구합니다, 그러나 브라우저는 <code>mailto:</code> (메일 클라이언트를 열기 위한) 또는 파일을 전송하기 위해 <code>ftp:</code> 와 같은 다른 프로토콜들을 다루는 법 또한 알고 있습니다, 그러므로 만약 이런 프로토콜들을 보더라도 놀라지 마십시오.</dd> + <dt><img alt="Domaine Name" src="https://mdn.mozillademos.org/files/8015/mdn-url-domain@x2.png" style="height: 70px; width: 440px;"></dt> + <dd><code>www.example.com</code> 은 도메인 이름입니다. 이것은 어떤 웹 서버가 요구되는 것인 지를 가리킵니다. 대안으로, 직접 {{Glossary("IP address")}}를 사용하는 것도 가능합니다, 그러나 덜 편리하기 때문에, 그것은 웹에서 주로 사용되지는 않습니다.</dd> + <dt><img alt="Port" src="https://mdn.mozillademos.org/files/8017/mdn-url-port@x2.png" style="height: 70px; width: 440px;"></dt> + <dd><code>:80</code> 은 포트입니다. 이것은 기술적으로 웹서버에서 자원을 접근하기 위해 사용하는 "관문(gate)"을 가리킵니다. 만약 웹서버가 자원의 접근 하기 위해 표준 HTTP 포트 (HTTP를 위한 80, HTTPS를 위한 443)를 사용한다면, 포트 번호는 보통 생략합니다. 그렇지 않으면 포트 번호는 필수입니다.</dd> + <dt><img alt="Path to the file" src="https://mdn.mozillademos.org/files/8019/mdn-url-path@x2.png" style="height: 70px; width: 440px;"></dt> + <dd><code>/path/to/myfile.html</code> 은 웹서버에서 자원에 대한 경로입니다. 초기의 웹에서는, 웹서버상에서 물리적 파일 위치를 나타냈습니다. 요즘에는, 실제 물리적 경로를 나타내지 않고, 웹 서버에서 추상화하여 보여줍니다.</dd> + <dt><img alt="Parameters" src="https://mdn.mozillademos.org/files/8021/mdn-url-parameters@x2.png" style="height: 70px; width: 440px;"></dt> + <dd><code>?key1=value1&key2=value2</code> 는 웹서버에 제공하는 추가 파라미터입니다. 이 파라미터들은 <code>&</code> 기호로 구분된 키/값으로 짝을 이룬 리스트입니다. 웹 서버는 자원을 반환하기 전에 추가적인 작업을 위해 이런 파라미터들을 사용할 수 있습니다. 각각의 웹서버는 파라미터들을 언급하는 자신의 규칙을 갖고 있습니다. 그리고, 특정한 웹서버가 파라미터를 다루는 지 알기 위한 유일한 방법은 웹서버 소유자에게 묻는 것입니다.</dd> + <dt><img alt="Anchor" src="https://mdn.mozillademos.org/files/8023/mdn-url-anchor@x2.png" style="height: 70px; width: 440px;"></dt> + <dd><code>#SomewhereInTheDocument</code> 는 자원 자체의 다른 부분에 대한 anchor(닻) 입니다. An anchor 는 일종의 자원 안에서 "bookmark" 입니다. 즉, "bookmarked" 지점에 위치된 내용을 보여주기 위해 브라우저에게 방향을 알려줍니다. 예를 들어, HTML 문서에서 브라우저는 anchor가 정의한 곳의 점을 스크롤할 것입니다; 비디오나 오디오 문서에서, 브라우저는 앵커가 나타내는 시간을 찾으려 할 것입니다. <strong>#</strong>뒤에 오는 부분은 가치가 없습니다. 또한,<em> <strong>fragment identifier(부분 식별자)</strong> 라고 알려져, 요청이 서버에 절대 보내지지 않습니다.</em></dd> +</dl> + +<p>{{Note('URLs을 말하면 <a href="http://en.wikipedia.org/wiki/Uniform_Resource_Locator">몇몇의 추가적인 부분과 규칙</a>이 있다, 그러나 그것들은 일반적인 유저와 웹 개발자들에게 상관이 없다. 이것에 대해 걱정하지 말고, 완전한 기능적인 URLs를 구축하고 사용하기 위해 알 필요는 없다.')}}</p> + +<p>당신은 일반적인 우편 메일 주소처럼 URL을 생각할 것이다: <em>프로토콜</em>은 사용하고 싶은 우편 서비스다, <em>도메인 이름</em>은 도시나 마을이다, 그리고 <em>포트</em> 우편 번호이다; <em>경로</em>는 메일이 전달되어야 하는 건물을 나타낸다; <em>파라미터</em>는 건물 번호와 같은 정보를 나타낸다; 그리고, 마지막으로, <em>anchor(앵커)</em>는 메일을 받는 실제 사람을 나타낸다.</p> + +<h3 id="URLs_을_사용하는_법">URLs 을 사용하는 법</h3> + +<p>어떤 URL이든 자원을 얻기 위해 브라우저의 주소창에 올바르게 적으면 된다!</p> + +<p>{{Glossary("HTML")}} 언어 — <a href="/en-US/docs/Learn/HTML/HTML_tags">나중에 이야기할 것</a> — 가 URLs을 광범위하게 사용하게 만들었다:</p> + +<ul> + <li>{{HTMLElement("a")}} 요소로 다른 문서와의 링크를 만들기 위해;</li> + <li>{{HTMLElement("link")}} 또는 {{HTMLElement("script")}}처럼 다양한 요소를 통해서 관련된 자원을 가진 문서를 연결시키기 위해;</li> + <li>이미지 ({{HTMLElement("img")}} 요소), 비디오 ({{HTMLElement("video")}} 요소), 소리 또는 음악 ({{HTMLElement("audio")}} 요소), 등과 같은 미디어를 보여주기 위해;</li> + <li>{{HTMLElement("iframe")}} 요소를 다른 HTML 문서에 보여주기 위해.</li> +</ul> + +<div class="note"> +<p><strong>Note:</strong> 한 페이지의 일부로서, 자원을 불러오기 위해 URLs 특정할 때, (<code><script></code>, <code><audio></code>, <code><img></code>, <code><video></code>, 와 같은 것을 사용할 때 처럼), 오직 HTTP와 HTTPS URL을 사용해야만 한다. 예를 들어, FTP를 사용하는 것은 부분적으로 안전하지 않고, 더 이상 많은 브라우저에서 지원하지 않는다.</p> +</div> + +<p>{{Glossary("CSS")}} 또는 {{Glossary("JavaScript")}}와 같은 다른 기술들은 URLs를 광범위하게 사용한다 그리고, 이런 것들이 정말로 웹의 심장이다.</p> + +<h3 id="절대_URLs_vs_상대_URLs">절대 URLs vs 상대 URLs</h3> + +<p>우리가 위에서 얘기한 것은 <em>절대 URL</em> 이다. 그러나 또한 <em>상대 URL</em>도 있다. 그 차이가 의미하는 것을 더 자세히 알아봅시다.</p> + +<p>요구한 부분의 URL은 URL이 사용되는 문맥에서 크게 의존한다. 브라우저의 주소바에서, URL은 어떤 문맥도 가지고 있지 않다, 그래서 위에서 본 것 처럼 전체 (또는 <em>절대</em>) URL을 제공해야 한다. 프로토콜(브라우저는 기본적으로 HTTP 를 사용한다)또는 포트(해당 웹서버가 몇몇의 흔치 않은 포트를 사용할 때만 요구한다.)를 포함할 필요는 없다. 그러나, URL의 모든 다른 부분(part)은 필요하다.</p> + +<p>URL이 HTML 페이지와 같은 문서 내에서 사용될 때는 조금 다르다. 왜냐하면, 브라우저는 이미 문서의 자체 URL을 갖고 있기 때문에, 문서 내에서 이용가능한 어떤 URL의 잃어버린 부분(part)에 정보를 채우기 위해 사용한다. 오직 URL의 <em>path </em>부분을 보면, <em>절대 URL</em>과 <em>상대 URL</em>을 구별할 수 있다. 만약 URL의 경로 부분이 <code>"/</code>" 문자로 시작한다면, 그 브라우저는 현재 문서에서 주어진 문맥에서 참조없이, 서버의 루트(top root)에서 자원을 가지고 올 것이다.</p> + +<p>더 분명하게 알기 위해 예제를 봅시다.</p> + +<h4 id="절대_URLs의_예">절대 URLs의 예</h4> + +<dl> + <dt>전체 URL (이전에 사용한 것과 같은)</dt> + <dd> + <pre>https://developer.mozilla.org/en-US/docs/Learn</pre> + </dd> + <dt>내포된 프로토콜</dt> + <dd> + <pre>//developer.mozilla.org/en-US/docs/Learn</pre> + + <p>이 경우에, 브라우저는 URL을 호스팅한 문서를 불러오기 위해 사용한 것과 같은 프로토콜을 가진 URL을 부를 것이다.</p> + </dd> + <dt>내포된 도메인명</dt> + <dd> + <pre>/en-US/docs/Learn</pre> + + <p>이것은 HTML 문서 내에서 절대 URL을 위한 가장 흔한 사용법이다. 브라우저는 같은 프로토콜과 그 URL을 호스팅한 문서를 불러오기 위해 사용한 것과 같은 도메인명을 사용할 것이다. <strong>Note:</strong> <em>프로토콜을 생략하는 것 없이, 도메인명을 생략하는 것을 가능하지 않다</em>.</p> + </dd> +</dl> + +<h4 id="상대_URLs의_예">상대 URLs의 예</h4> + +<p>다음의 예를 더 잘 이해하기 위해, URL은 다음의 URL이 위치한 문서 내에서 불린다고 가정해봅시다: <code>https://developer.mozilla.org/en-US/docs/Learn</code></p> + +<dl> + <dt>Sub-resources</dt> + <dd> + <pre>Skills/Infrastructure/Understanding_URLs +</pre> + URL이 <code>/</code>로 시작하지 않기 때문에, 브라우저는 현재 자원을 포함하는 서브 디렉토리에 있는 문서를 찾으려 할 것이다. 그래서 예를 들어, 이 URL에 도달하길 원하는 것이다: <code>https://developer.mozilla.org/en-US/docs/Learn/Skills/Infrastructure/Understanding_URLs</code></dd> + <dt>디렉토리 트리에서 뒤로 가기</dt> + <dd> + <pre>../CSS/display</pre> + + <p>이 경우에, <code>../</code> 를 쓰는 것을 관례로 사용한다 — UNIX 파일 시스템에서 유래했다 — 브라우저에게 한 디렉토리에서 상위로 가고 싶다고 말하는 것이다. 여기서, 이 URL에 도달하고 싶은 것이다: <code>https://developer.mozilla.org/en-US/docs/Learn/../CSS/display</code>, 이렇게 단순화 된다: <code>https://developer.mozilla.org/en-US/docs/CSS/display</code></p> + </dd> +</dl> + +<h3 id="Semantic(의미있는)_URLs">Semantic(의미있는) URLs</h3> + +<p>매우 기술적인 것에도 불구하고, URLs은 웹 사이트를 위한 인간이 읽을 수 있는 시작점을 나타낸다. URL은 저장될 수 있고, 누군가가 URL을 주소바에 기입할 수 있다. 사람들이 웹에 핵심에 있다. 그리고, <a href="http://en.wikipedia.org/wiki/Semantic_URL"><em>semantic URLs</em></a>이라 불리는 것을 구축하기 위해 최선을 고려한다. Semantic URLs은 기술적인 노하우와 상관없이 누구나 이해할 수 있게 하는 의미로 단어들을 사용한다.</p> + +<p>언어학적 의미론(Semantics)은 컴퓨터와 상관없는 코스다. 아마도 자주 임의의 문자들의 조합처럼 보이는 URL을 봤을 것이다. 그러나 인간이 읽을 수 있는 URL들을 만드는 것에는 많은 장점이 있다:</p> + +<ul> + <li>당신이 URL을 조작하기 쉽게 한다.</li> + <li>어디에 있고, 무엇을 하고, 무엇을 읽거나 웹에서 상호작용하는 지에 대해 유저들에게 분명히 알려준다.</li> + <li>몇몇의 검색엔진은 관련 페이지들을 잘 분류하기 위해 이런 의미론을 사용할 수 있다.</li> +</ul> + +<h2 id="다음_단계">다음 단계</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Understanding_domain_names">도메인 명 이해하기</a></li> +</ul> diff --git a/files/ko/learn/common_questions/what_is_a_web_server/index.html b/files/ko/learn/common_questions/what_is_a_web_server/index.html new file mode 100644 index 0000000000..9e57fc8391 --- /dev/null +++ b/files/ko/learn/common_questions/what_is_a_web_server/index.html @@ -0,0 +1,118 @@ +--- +title: 웹 서버란 무엇일까? +slug: Learn/Common_questions/What_is_a_web_server +translation_of: Learn/Common_questions/What_is_a_web_server +--- +<div class="summary"> +<p>여기서 우리는 웹 서버가 무엇인지, 어떻게 동작하는지, 왜 중요한지를 알아볼 것입니다.</p> +</div> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">선수 지식:</th> + <td><a href="/en-US/docs/Learn/page_vs_site_vs_server_vs_search_engine">web page와 web site, web server, 그리고 search engine의 차이점</a>에 대해 이해하고 <a href="/en-US/docs/Learn/How_the_Internet_works">인터넷이 어떻게 동작하는지</a>를 이미 알아야 합니다.</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>web server가 무엇인지를 배우고, 어떻게 동작하는지에 대한 전반적인 이해를 얻을 것입니다.</td> + </tr> + </tbody> +</table> + +<h2 id="요약">요약</h2> + +<p>"Web server"는 하드웨어, 소프트웨어 혹은 두 개가 같이 동작하는 것을 의미할 수 있습니다. </p> + +<ol> + <li>하드웨어 측면에서, web server는 web server의 소프트웨어와 website의 컴포넌트 파일들을 저장하는 컴퓨터입니다. (컴포넌트 파일에는 HTML 문서, images, CSS stylesheets, 그리고 JavaScript files가 있습니다.) Web server는 인터넷에 연결되어 웹에 연결된 다른 기기들이 웹 서버의 데이터(컴포넌트 파일들)를 주고받을 수 있도록 합니다.</li> + <li>소프트웨어 측면에서, web server는 기본적으로 웹 사용자가 어떻게 호스트 파일들에 접근하는지를 관리합니다. 이 문서에서 web server는 HTTP서버로 국한합니다. HTTP 서버는 URL(Web addresses)과 HTTP(당신의 브라우저가 웹 페이지를 보여주기 위해 사용하는 프로토콜)의 소프트웨어 일부입니다.</li> +</ol> + +<p>가장 기본적인 단계에서, 브라우저가 웹 서버에서 불려진 파일을 필요로 할때, 브라우저는 HTTP를 통해 파일을 요청합니다. 요청이 올바른 웹 서버(하드웨어)에 도달하였을 때, HTTP 서버(software)는 요청된 문서를 HTTP를 이용해 보내줍니다. </p> + +<p><img alt="Basic representation of a client/server connection through HTTP" src="https://mdn.mozillademos.org/files/8659/web-server.svg" style="height: 200px; width: 600px;"></p> + +<p>웹 사이트를 공개하기 위해서는, 당신은 정적 혹은 동적 웹 서버가 필요합니다.</p> + +<p>정적 웹 서버 혹은 스택은 HTTP 서버 (소프트웨어)가 있는 컴퓨터(하드웨어)로 구성되어 있습니다. 서버가 그 불려진 파일을 당신의 브라우저에게 전송하기 때문에, 저희는 그것을 "정적"이라고 부릅니다.</p> + +<p>동적 웹 서버는 정적 웹 서버와 추가적인 소프트웨어(대부분 일반적인 애플리케이션 서버와 데이터베이스)로 구성되어 있습니다. 애플리케이션 서버가 HTTP 서버를 통해 당신의 브라우저에게 불려진 파일들을 전송하기 전에, 애플리케이션 서버가 업데이트하기 때문에 우리는 이것을 동적이라고 부릅니다.</p> + +<p>예를 들어, 당신이 브라우저에서 보는 최종 웹페이지들을 생성하기 위해, 애플리케이션 서버는 아마 데이터베이스로 온 컨텐츠들로 이루어진 HTML 템플릿을 채울지 모릅니다. MDN 혹은 Wikipedia와 같은 사이트들은 수 천개의 웹페이지들을 가지고 있지만, 그것들은 실제의 HTML 문서가 아니라 오직 약간의 HTML 템플릿과 엄청 큰 데이터베이스로 되어있습니다. 이 구성은 내용들을 전달하고 관리하기 쉽고 빠르게 만들어 줍니다.</p> + +<h2 id="활발한_교육">활발한 교육</h2> + +<p>아직 자료가 없습니다. 부디 <a href="https://developer.mozilla.org/en-US/docs/MDN/Getting_started">기여하여주세요</a>.</p> + +<h2 id="더_깊은_부분">더 깊은 부분</h2> + +<p>웹 페이지를 가져오기 위해, 우리가 이미 말했듯이, 당신의 브라우저는 저장 공간에 있는 요청된 파일들을 찾는 웹 서버에게 요청을 보냅니다. 한번 좀더 자세히 알아봅시다. </p> + +<h3 id="호스팅_파일들">호스팅 파일들</h3> + +<p>웹 서버는 처음에 HTML 문서라고 불리는 웹 사이트의 파일들과 이미지, CSS 스타일시트, JavaScript 파일, 폰트, 비디오를 포함한 관련된 것들을 저장해야합니다. </p> + +<p>기술적으로, 당신은 컴퓨터에 있는 그 파일들을 불러올수 있지만, 그것들을 전담하는 웹 서버에 저장하는것이 훨씬 더 편리합니다. 전담하는 웹서버는: </p> + +<ul> + <li>항상 실행 중입니다</li> + <li>항상 인터넷과 연결되어 있습니다</li> + <li>항상 같은 IP주소를 가지고 있습니다(모든 {{Glossary("ISP", "ISPs")}}가 홈 라인에 대해 고정된 IP주소를 제공하는 것은 아닙니다.)</li> + <li>제 3자에 의해 유지보수 됩니다</li> +</ul> + +<p>이러한 이유들로, 좋은 호스팅 제공자를 찾는 것은 당신의 웹 사이트를 구축하는 것의 핵심 부분입니다. 다양한 서비스 회사들의 조건을 살펴보고 당신의 필요와 예산을 충족하는 하나를 선택하세요 (서비스는 무료부터 매달 수 백만원까지 있습니다.) 더 많은 자세한 사항은 <a href="https://developer.mozilla.org/en-US/Learn/How_much_does_it_cost#Hosting">여기서 </a>찾을 수 있습니다.</p> + +<p>당신이 웹 호스팅 솔루션을 설정했다면, 그저 당신의 <a href="/en-US/docs/Learn/Upload_files_to_a_web_server">웹 서버에 파일들을 업로드 하시면 됩니다.</a></p> + +<h3 id="HTTP를_이용해_통신하기">HTTP를 이용해 통신하기</h3> + +<p>두 번째로, 웹 서버는 {{Glossary("HTTP")}} (hypertext transfer protocol)을 위한 지원합니다. 이름이 의미하듯이, HTTP는 어떻게 두 컴퓨터간의 hypertext(예를 들어, 연결된 웹 문서)를 전송하는지를 서술합니다.</p> + +<p>프로토콜은 두 컴퓨터간의 통신를 위한 규칙의 집합입니다. HTTP는 문자로 된, 독립적인 프로토콜입니다.</p> + +<dl> + <dt>Textual(문자로 된)</dt> + <dd>모든 명령어들은 기본 문자이며 사람들이 읽을 수 있습니다. </dd> + <dt>Stateless(독립적인)</dt> + <dd>서버 혹은 클라이언트는 이전의 통신을 기억하지 않습니다. 예를 들어, HTTP에만 의존하면, 서버는 당신이 입력한 비밀번호 혹 당신이 처리한 단계를 기억하지 못합니다. 당신은 그러한 일들을 위한 애플리케이션 서버가 필요합니다. (우리는 그러한 기술을 뒤에 나올 기사에서 다룰 것입니다.)</dd> +</dl> + +<p>HTTP는 어떻게 클라이언트와 서버가 통신을 하는지 명확한 규칙을 제공합니다. 우리는 HTTP 그 자체를 나중에 <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP">technical article</a> 에서 다룰 것입니다. 현재는, 이러한 것들을 기억해주세요.</p> + +<ul> + <li>오직 클라이언트만이 HTTP 요청을 만들 수 있으며, 서버에게만 보낼 수 있습니다. 서버는 오직 클라이언트의 HTTP 요청에 응답할 수 있습니다. </li> + <li>HTTP를 통해 파일을 요청할때, 클라이언트는 반드시 {{Glossary("URL")}} 파일들을 제공해야 합니다.</li> + <li><font color="#3B3C40" face="Open Sans, Arial, sans-serif">웹 서버는 반드시 </font><font color="#3B3C40" face="Open Sans, Arial, sans-serif">최소한의 에러 메시지를 포함하여</font> <font color="#3B3C40" face="Open Sans, Arial, sans-serif">모든 HTTP 요청에 응답해야합니다. </font></li> +</ul> + +<p><a href="https://developer.mozilla.org/en-US/404"><img alt="The MDN 404 page as an example of such error page" src="https://mdn.mozillademos.org/files/8661/mdn-404.jpg" style="float: right; height: 300px; width: 300px;"></a>웹 서버에서, HTTP 서버는 들어오는 요청들에 대해 응답하고, 처리해야 합니다. </p> + +<ol> + <li>요청을 받으면, HTTP 서버는 먼저 요청받은 URL이 존재하는 파일과 매칭이 되는지를 확인합니다.</li> + <li> + <p>만약 매칭된다면, 웹 서버는 그 파일 내용을 브라우저에게 되돌려줍니다. 만약 그렇지 않다면, 애플리케이션 서버는 필요한 파일을 구축합니다.</p> + </li> + <li>만약 위 둘의 과정이 불가능하다면, 웹 서버는 브라우저에게 에러 메시지를 반환합니다, 대부분의 에러 메시지는 "404 Not Found" 입니다.(이 에러는 너무 많이 발생하여 많은 웹 디자이너들은<a href="http://www.404notfound.fr/" rel="external">404 error pages</a>를 디자인하는데 많은 시간을 할애합니다. </li> +</ol> + +<h3 id="정적_vs._동적_컨텐츠">정적 vs. 동적 컨텐츠</h3> + +<p>대략적으로 말하자면, 서버는 정적 혹은 동적 컨텐츠 모두 제공할 수 있습니다. "정적"은 "있는 그대로 제공되는 것(served as-is)"를 의미합니다. 정적 웹 사이트들은 설치하기 가장 쉽기때문에 우리는 당신이 첫 사이트를 정적 사이트로 만들기를 제안합니다.</p> + +<p>"동적"은 서버가 컨텐츠를 처리하는 것, 심지어는 컨텐츠를 데이터베이스로부터 생성하는 것을 의미합니다. 이 방법은 더 많은 유연성을 제공하지만, 기술적 스택이 더 다루기 힘들어지고, 웹사이트를 구축하는 것이 훨씬 더 복잡해집니다.</p> + +<p>당신이 지금 읽고있는 페이지를 예시로 봅시다. 이 사이트를 호스팅하고 있는 웹 서버에는, 데이터베이스로부터 내용들을 받고, 구성하고, HTML 템플릿 안에 집어넣고, 당신에게 결과를 보내는 애플리케이션 서버가 있습니다. 이러한 경우, 애플리케이션 서버는 <a href="https://developer.mozilla.org/en-US/docs/MDN/Kuma">Kuma</a>라고 불리고, <a href="https://www.python.org/">Python</a>(<a href="https://www.djangoproject.com/">Django</a> 프레임워크를 이용한)으로 구축됩니다. Mozilla 팀은 MDN의 특수한 목적으로 Kuma를 만들었지만, 많은 다른 기술들로 만들어진 비슷한 애플리케이션이 존재합니다.</p> + +<p>애플리케이션 서버는 아주 많이 있어서 특정한 하나만 추천하기는 어렵습니다. 어떤 애플리케이션 서버는 블로그나 위키, 인터넷 쇼핑, {{Glossary("CMS", "CMSs")}}라고 불리는 다른 것들(컨텐츠 관리 시스템) 같은 특수한 웹 사이트에 특화되어 있습니다. 만약 당신이 동적 웹 사이트를 구축한다면, 당신의 필요에 맞는 도구를 선택하는 시간을 가져보세요. 웹 서버 프로그래밍을 배우기를 원하는 경우가 아니라면(믈론, 그 자체로도 흥미진진한 영역입니다!), 애플리케이션 서버를 새로 만들 필요가 없습니다. 그것은 휠을 다시 재발명 하는 것과 같은 일입니다.</p> + +<h2 id="다음_과정">다음 과정</h2> + +<p>이제 당신은 웹 서버에 익숙해졌으니, 아래와 같은 것들을 할 수 있습니다:</p> + +<ul> + <li><a href="/en-US/docs/Learn/How_much_does_it_cost">웹에서 어떤 것을 하는 것이 얼마나 많은 비용이 들지</a>를 읽어보기</li> + <li><a href="/en-US/docs/Learn/What_software_do_I_need.">당신이 웹 사이트를 생성하기 위해 필요한 다양한 소프트웨어</a>를 배우기</li> + <li><a href="/en-US/docs/Learn/Upload_files_to_a_web_server">웹 서버에 어떻게 파일을 업로드 하는 지</a>와 같은 실용적인 것으로 넘어가기</li> +</ul> diff --git a/files/ko/learn/common_questions/what_software_do_i_need/index.html b/files/ko/learn/common_questions/what_software_do_i_need/index.html new file mode 100644 index 0000000000..f50ef17dd2 --- /dev/null +++ b/files/ko/learn/common_questions/what_software_do_i_need/index.html @@ -0,0 +1,180 @@ +--- +title: What software do I need to build a website? +slug: Learn/Common_questions/What_software_do_I_need +tags: + - 초보자 +translation_of: Learn/Common_questions/What_software_do_I_need +--- +<div class="summary"> +<p>이 글에서, 우리는 당신이 편집하고, 업로드하고, 웹사이트를 볼 때 어떤 소프트웨어 구성품이 필요한 지 제시한다.</p> +</div> + +<table class="learn-box nostripe standard-table"> + <tbody> + <tr> + <th scope="row">요구사항:</th> + <td><a href="/en-US/docs/Learn/page_vs_site_vs_server_vs_search_engine">웹페이지, 웹사이트, 웹서버, 검색엔진의 차이</a>를 알아야 한다.</td> + </tr> + <tr> + <th scope="row">목적:</th> + <td>만약 당신이 웹사이트를 편집하거나 업로드하거나 볼 때, 필요한 소프트웨어 구성품이 무엇인지 배웁니다.</td> + </tr> + </tbody> +</table> + +<h2 id="요약">요약</h2> + +<p>당신은 웹 개발에 필요한 대부분의 프로그램들을 무료로 다운 받을 수 있습니다. 우리는 이 글에서 몇 개의 링크를 제공할 것입니다. 당신은 1) 웹페이지를 생성하고 편집하기, 2) 웹 서버에 파일을 업로드하기, 3) 웹 페이지 보기 를 위한 툴들이 필요할 것입니다.</p> + +<p>거의 모든 운영체제는 기본적으로 텍스트 에디터와 웹 뷰어(브라우저)를 포함하고 있습니다. 그래서 보통 웹 서버로 파일을 전송할 소프트웨어 필요합니다.</p> + +<h2 id="Active_Learning">Active Learning</h2> + +<p><em>There is no active learning available yet. <a href="/en-US/docs/MDN/Getting_started">Please, consider contributing</a>.</em></p> + +<h2 id="깊게_들어가기">깊게 들어가기</h2> + +<h3 id="웹_페이지를_생성하고_편집하기">웹 페이지를 생성하고 편집하기</h3> + +<p>웹사이트를 생성하고 편집하기 위해, 텍스트 에디터가 필요합니다. 텍스트 에디터는 무서식의 텍스트 파일을 생성하고 수정합니다. (<strong>{{Glossary("RTF")}}</strong> 같은 다른 형식(format)들은, 볼드체와 밑줄같은 포멧을 추가하게 합니다. 이런 포맷들은 웹 페이지를 쓰는 데 적합하지 않습니다.) 당신은 현명하게 텍스트 에디터를 선택해야 합니다. 왜냐하면, 웹사이트를 구축하는 동안에, 광범위하게 사용해야하기 때문입니다.</p> + +<p>모든 데스크탑 운영체제는 기본적인 텍스트 에디터가 딸려 있습니다. 이런 에디터들은 모두 간단하지만, 웹페이지 코딩에 특별한 기능들이 부족합니다. 만약 당신이 더 복잡한 것을 원한다면, 많은 이용가능한 다른(third-party) 툴들이 있습니다. 서드-파티 에디터들은 구문 색표시, 자동완성, 섹션접기, 코드검색을 포함하는 추가 기능이 딸려 있습니다. 에디터들의 간략한 리스트입니다:</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">운영 체제</th> + <th scope="col">내장 에디터</th> + <th scope="col">Third-party 에디터</th> + </tr> + </thead> + <tbody> + <tr> + <td>Windows</td> + <td><a href="http://en.wikipedia.org/wiki/Notepad_%28software%29" rel="external">Notepad</a></td> + <td> + <p><a href="http://notepad-plus-plus.org/">Notepad++</a></p> + + <p><a href="https://www.visualstudio.com/">Visual Studio Code</a></p> + + <p><a href="https://www.jetbrains.com/webstorm/">Web Storm</a></p> + + <p><a href="http://brackets.io/">Brackets</a></p> + + <p><a href="https://shiftedit.net/">ShiftEdit</a></p> + </td> + </tr> + <tr> + <td>Mac OS</td> + <td><a href="http://en.wikipedia.org/wiki/TextEdit" rel="external">TextEdit</a></td> + <td> + <p><a href="http://www.barebones.com/products/textwrangler/">TextWrangler</a></p> + + <p><a href="https://www.visualstudio.com/">Visual Studio Code</a></p> + + <p><a href="http://brackets.io/">Brackets</a></p> + + <p><a href="https://shiftedit.net/">ShiftEdit</a></p> + </td> + </tr> + <tr> + <td>Linux</td> + <td><a href="http://en.wikipedia.org/wiki/Vi" rel="external">Vi</a> (All UNIX)<br> + <a href="http://en.wikipedia.org/wiki/Gedit" rel="external">GEdit</a> (Gnome)<br> + <a href="http://en.wikipedia.org/wiki/Kate_%28text_editor%29" rel="external">Kate</a> (KDE)<br> + <a href="http://en.wikipedia.org/wiki/Kate_(text_editor)" rel="external">LeafPad</a> (Xfce)</td> + <td> + <p><a href="http://www.gnu.org/software/emacs/">Emacs</a><br> + <a href="http://www.vim.org/" rel="external">Vim</a></p> + + <p><a href="https://www.visualstudio.com/">Visual Studio Code</a></p> + + <p><a href="http://brackets.io/">Brackets</a></p> + + <p><a href="https://shiftedit.net/">ShiftEdit</a></p> + </td> + </tr> + <tr> + <td>Chrome OS</td> + <td> </td> + <td><a href="https://shiftedit.net/">ShiftEdit</a></td> + </tr> + </tbody> +</table> + +<p>이것은 하나의 고급 텍스트 에디터의 스크린샷입니다:</p> + +<p><img alt="Screenshot of Notepad++." src="https://mdn.mozillademos.org/files/8221/NotepadPlusPlus.png" style="height: 311px; width: 450px;"> </p> + +<p>이것은 온라인 텍스트 에디터의 스크린샷입니다:</p> + +<p><img alt="Screenshot of ShiftEdit" src="https://mdn.mozillademos.org/files/15837/shiftedit.png" style="height: 311px; width: 475px;"></p> + +<h3 id="웹에_파일_업로드하기">웹에 파일 업로드하기</h3> + +<p>당신의 웹사이트가 대중들에게 보여지기 전에, 웹 서버에 웹페이지를 업로드 해야할 것입니다. 당신은 다양한 제공장로부터 서버의 공간을 살 수 있습니다. (<a class="new" href="/en-US/docs/Learn/How_much_does_it_cost">How much does it cost to do something on the web?</a>를 보십시오). 일단, 당신이 어떤 제공자를 사용할 지 정했다면, 제공자는 당신에게 FTP(파일 전송 프로토콜) 접근 정보를 이메일로 보낼 것입니다.웹 사이트를 만들 때, 웹 서버에 파일을 업로드 하는 것은 매우 중요한 단계입니다, 그래서 우리는 상세한 부분은 <a href="/en-US/docs/Learn/Upload_files_to_a_web_server">a separate article(따로 분리한 글)</a>에서 다루겠습니다. 아래는 무료 기본 FTP 클라이언트의 목록입니다:</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">운영체제</th> + <th colspan="2" rowspan="1" scope="col" style="text-align: center;"> FTP 소프트웨어</th> + </tr> + </thead> + <tbody> + <tr> + <td>Windows</td> + <td> + <p><a href="http://winscp.net" rel="external">WinSCP</a></p> + + <p><a href="http://mobaxterm.mobatek.net/">Moba Xterm</a></p> + </td> + <td colspan="1" rowspan="3"> + <p><a href="https://filezilla-project.org/">FileZilla</a> (All OS)</p> + + <p> </p> + </td> + </tr> + <tr> + <td>Linux</td> + <td><a href="https://live.gnome.org/Nautilus" rel="external">Nautilus</a> (Gnome)<br> + <a href="http://dolphin.com/" rel="external">Dolphin</a> (KDE)</td> + </tr> + <tr> + <td>Mac OS</td> + <td><a href="http://cyberduck.de/">Cyberduck</a></td> + </tr> + <tr> + <td>Chrome OS</td> + <td><a href="https://shiftedit.net/">ShiftEdit</a> (All OS)</td> + <td colspan="1"> </td> + </tr> + </tbody> +</table> + +<h3 id="웹사이트_보기">웹사이트 보기</h3> + +<p>알다시피, 웹사이트를 보기 위해 웹 브라우저가 필요합니다. 개인적인 사용을 위한 <a href="http://en.wikipedia.org/wiki/List_of_web_browsers">수 십개</a>의 브라우저 선택권이 있습니다. 그러나, 웹 사이트를 개발할 때, 대부분의 사람들이 당신의 사이트를 잘 이용하기 위해서는 다음의 주요 브라우저에서 테스트해야합니다.</p> + +<ul> + <li><a href="https://www.mozilla.org/en-US/firefox/new/" rel="external">Mozilla Firefox(파이어폭스)</a></li> + <li><a href="https://www.google.fr/chrome/browser/" rel="external">Google Chrome(크롬)</a></li> + <li><a href="http://windows.microsoft.com/en-US/internet-explorer/download-ie" rel="external">Microsoft Internet Explorer(인터넷 익스플로러)</a></li> + <li><a href="http://www.apple.com/safari/" rel="external">Apple Safari(사파리)</a></li> +</ul> + +<p>만약 당신이 기술적인 플랫폼이나 국가 등 특정한 그룹을 목적으로 한다면, <a href="http://www.opera.com/" rel="external">Opera</a>, <a href="http://www.konqueror.org/">Konqueror</a>,<a href="http://www.ucweb.com/ucbrowser/" rel="external"> UC Browser</a> 같은 추가적인 브라우저도 테스트해야할 지도 모릅니다.</p> + +<p>그러나 몇몇의 브라우저는 특정한 운영체제에서만 동작하기 때문에 테스트하는 것이 복잡합니다. 애플의 사파리는 iOS와 Max OS 에서만 동작하는 반면에, 인터넷 익스플로러는 윈도우에서만 동작합니다. <a href="http://browsershots.org/" rel="external">Browsershots</a>나 <a href="http://www.browserstack.com/" rel="external">Browserstack</a> 같은 서비스를 이용하는 것이 좋습니다. Browsershots은 다양한 브라우저에서 볼 때, 웹사이트의 스크린샷을 제공합니다. Browserstack은 사실 당신에게 가상머신에서 완전한 원거리 접근을 가능하게 해줍니다. 그래서 당신은 대부분의 공통 환경에서 사이트를 테스트할 수 있습니다. 그렇지 않으면, 당신 자신의 가상 머신을 설치하면 됩니다. 하지만 이것은 약간의 전문지식이 필요한 작업입니다. (만약 당신이 이런 길을 가고자 한다면, 마이크로소프트에서는 <a href="https://modern.ie" rel="external">modern.ie</a>.에서 사용 준비가 완료된 가상 머신이 포함된 개발자를 위한 툴들을 가지고 있습니다.)</p> + +<p>물론, 실제 장치에서 몇 번의 테스트를 해봐야한다. 특히, 실제 모바일 장치에서는. 모바일 장치 시뮬레이션은 새롭고, 진화하고 있는 기술이고 데스트탑 시뮬레이션보다 신뢰가 떨어진다. 물론, 모바일 장치는 돈이 든다. 그래서 우리는<a href="http://opendevicelab.com/" rel="external">Open Device Lab initiative</a>에서 보는 것을 제안한다. 당신이 너무 많은 소비없이 많은 플랫폼을 테스트하고 싶다면, 장치를 공유할 수 있다.</p> + +<h2 id="다음_단계">다음 단계</h2> + +<ul> + <li>몇몇의 소프트웨어는 무료이나, 모두 무료는 아니다. <a href="/en-US/docs/Learn/Common_questions/How_much_does_it_cost">웹에서 무언가를 하기 위해 얼마나 비용이 드는 지 알아보기</a><a class="new" href="/en-US/docs/Learn/How_much_does_it_cost">.</a></li> + <li>당신이 더 많은 텍스트 에디터에 대해 배우고 싶다면, <a href="/en-US/docs/Learn/Choose,_Install_and_set_up_a_text_editor">텍스트 에디터를 선택하고 설치하는 법</a>에 대한 글을 읽으세요.</li> + <li>당신이 웹에서 웹사이트를 퍼블리싱하는 법에 대해 궁금하다면, <a href="/en-US/docs/Learn/Upload_files_to_a_web_server">"웹 서버에 파일을 업로드하는 법"</a>을 보십시오.</li> +</ul> + +<p> </p> diff --git a/files/ko/learn/common_questions/웹_사이트가_제대로_동작하는지_확인/index.html b/files/ko/learn/common_questions/웹_사이트가_제대로_동작하는지_확인/index.html new file mode 100644 index 0000000000..d39ea4069f --- /dev/null +++ b/files/ko/learn/common_questions/웹_사이트가_제대로_동작하는지_확인/index.html @@ -0,0 +1,170 @@ +--- +title: 웹 사이트가 제대로 동작하는지 확인하는 방법 +slug: Learn/Common_questions/웹_사이트가_제대로_동작하는지_확인 +translation_of: Learn/Common_questions/Checking_that_your_web_site_is_working_properly +--- +<div class="summary"> +<p>이번에는 웹사이트 동작과 관련한 다양한 문제해결 단계와 그 문제들을 해결하기 위한 방법들을 알아보겠습니다.</p> +</div> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">전제 조건:</th> + <td>먼저, <a href="/en-US/docs/Learn/Upload_files_to_a_web_server">upload files웹 서버에 파일 업로드 방법</a>을 알아야 합니다.</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>웹 사이트에서 발생할 수 있는 기본적인 문제들과 해결방법을 알아봅시다.</td> + </tr> + </tbody> +</table> + +<p id="Summary">개발하신 웹 사이트를 온라인상에 배포를 하였나요? 잘 했어요! 그런데 문제없이 동작하는게 확실한가요?</p> + +<p>종종 온라인에 배포한 웹 서버는 로컬에서 모습과는 꽤 다르게 동작할 때가 있습니다. 그 때문에 온라인에 배포할 때마다 한 번씩 확인이 필요합니다. 아마 많은 문제가 발생해 놀라게 될 텐데요: 이미지가 나오지 않거나, 페이지가 로딩이 안되거나 느리게 로딩되는 등 하는 문제들요. 대부분의 경우는 큰 문제가 아닙니다, 간단한 실수나 호스팅 세팅 같은 문제죠.</p> + +<p>이런 문제들을 어떻게 진단하고 해결하는지 살펴봅시다.</p> + +<h2 id="Active_Learning">Active Learning</h2> + +<p><em>There is no active learning available yet. <a href="/en-US/docs/MDN/Getting_started">Please, consider contributing</a>.</em></p> + +<h2 id="Dig_deeper">Dig deeper</h2> + +<h3 id="브라우저에서_테스트하기">브라우저에서 테스트하기</h3> + +<p>웹 사이트가 잘 동작하는지 알고 싶다면, 먼저 브라우저를 시작하고 테스트하려는 페이지로 이동하세요.</p> + +<h4 id="어_이미지가_어디갔죠">어?, 이미지가 어디갔죠?</h4> + +<p>우리의 개인 사이트를 봅시다.(동작x), <code>http://demozilla.examplehostingprovider.net/</code>. It's not showing the image we expected!</p> + +<p><img alt="Oops, the ‘unicorn’ image is missing" src="https://mdn.mozillademos.org/files/9643/image-missing.png" style="height: 189px; width: 380px;"></p> + +<p>Open Firefox's Network tool (<strong>Tools ➤ Web Developer ➤ Network</strong>) and reload the page:</p> + +<p><img alt="The image has a 404 error" src="https://mdn.mozillademos.org/files/9645/error404.png" style="height: 304px; width: 562px;"></p> + +<p>There's the problem, that "404" at the bottom. "404" means "resource not found", and that's why we didn't see the image.</p> + +<h4 id="HTTP_statuses">HTTP statuses</h4> + +<p>Servers respond with a status message whenever they receive a request. Here are the most common statuses:</p> + +<dl> + <dt><strong><span id="cke_bm_110S" style="display: none;"> </span>200: OK</strong></dt> + <dd>The resource you asked for was delivered.</dd> + <dt><strong>301: Moved permanently</strong></dt> + <dd>The resource has moved to a new location. You won't see this much in your browser, but it's good to know about "301" since search engines use this information a lot to update their indexes.</dd> + <dt><strong>304: Not modified</strong></dt> + <dd>The file has not changed since the last time you asked for it, so your browser can display the version from its cache, resulting in faster response times and more efficient use of bandwidth.</dd> + <dt><strong>403: Forbidden</strong></dt> + <dd>You aren't allowed to display the resource. Usually it has to do with a configuration mistake (e.g. your hosting provider forgot to give you access rights to a directory).</dd> + <dt><strong>404: Not found</strong></dt> + <dd>Self-explanatory. We'll discuss how to solve this below.</dd> + <dt><strong>500: Internal server error</strong></dt> + <dd>Something went wrong on the server. For instance, maybe the server-side language ({{Glossary("PHP")}}, .Net, etc.) stopped working, or the web server itself has a configuration problem. Usually it's best to resort to your hosting provider's support team.</dd> + <dt><strong>503: Service unavailable</strong></dt> + <dd>Usually resulting from a shortterm system overload. The server has some sort of problem. Try again in a little while.</dd> +</dl> + +<ul> +</ul> + +<p>As beginners checking our (simple) website, we'll deal most often with 200, 304, 403, and 404.</p> + +<h4 id="Fixing_the_404">Fixing the 404</h4> + +<p>So what went wrong?</p> + +<p><img alt="Le list of images in our project" src="https://mdn.mozillademos.org/files/9649/demozilla-images-list.png" style="height: 71px; width: 407px;"></p> + +<p>At first glance, the image we asked for seems to be in the right place... but the Network tool reported a "404". It turns out that we made a typo in our HTML code: <code>unicorn_pics.png</code> rather than <code>unicorn_pic.png</code>. So correct the typo in your code editor by changing the image's <code>src</code> attribute:</p> + +<p><img alt="Deleting the ‘s’" src="https://mdn.mozillademos.org/files/9651/code-correct.png" style="height: 125px; width: 775px;"></p> + +<p>Save, <a href="/en-US/Learn/Upload_files_to_a_web_server">push to the server</a>, and reload the page in your browser:</p> + +<p><img alt="The image loads corectly in the browser" src="https://mdn.mozillademos.org/files/9655/image-corrected.png" style="height: 554px; width: 565px;"></p> + +<p>There you go! Let's look at the {{Glossary("HTTP")}} statuses again:</p> + +<ul> + <li><strong>200</strong> for <code>/</code> and for <code>unicorn_pic.png</code> means that we succeeded in reloading the page and the image.</li> + <li><strong>304</strong> for <code>basic.css</code> means that this file has not changed since the last request, so the browser can use the file in its cache rather than receiving a fresh copy.</li> +</ul> + +<p>So we fixed the error and learned a few HTTP statuses along the way!</p> + +<h3 id="Frequent_errors">Frequent errors</h3> + +<p>The most frequent errors that we find are these:</p> + +<h4 id="Typos_in_the_address">Typos in the address</h4> + +<p>We wanted to type <code>http://demozilla.examplehostingprovider.net/</code> but typed too fast and forgot an “l”:</p> + +<p><img alt="Address unreachable" src="https://mdn.mozillademos.org/files/9657/cannot-find-server.png" style="height: 425px; width: 908px;"></p> + +<p>The address cannot be found. Indeed.</p> + +<h4 id="404_errors">404 errors</h4> + +<p>Many times the error just results just from a typo, but sometimes maybe you either forgot to upload a resource or you lost your network connection while you were uploading your resources. First check the spelling and accuracy of the file path, and if there's still a problem, upload your files again. That will likely fix the problem.</p> + +<h4 id="JavaScript_errors">JavaScript errors</h4> + +<p>Someone (possibly you) added a script to the page and made a mistake. This will not prevent the page from loading but you will feel something went wrong.</p> + +<p>Open the console (<strong>Tools ➤ Web developer ➤ Web Console</strong>) and reload the page:</p> + +<p><img alt="A Javascript error is shown in the Console" src="https://mdn.mozillademos.org/files/9659/js-error.png" style="height: 511px; width: 523px;"></p> + +<p>In this example, we learn (quite clearly) what the error is, and we can go fix it (we will cover JavaScript in <a href="/en-US/Learn/JavaScript">another series </a>of articles).</p> + +<h3 id="More_things_to_check">More things to check</h3> + +<p>We have listed a few simple ways to check that your website works properly, as well as the most common errors you may run across and how to fix them. You can also test if your page meets these criteria:</p> + +<h4 id="Hows_the_performance">How's the performance?</h4> + +<p>Does the page load fast enough? Resources like <a href="http://www.webpagetest.org/">WebPagetest.org</a> or browser add-ons like <a href="https://addons.mozilla.org/en-US/firefox/addon/yslow/">YSlow</a> can tell you a few interesting things:</p> + +<p><img alt="Yslow diagnostics" src="https://mdn.mozillademos.org/files/9661/yslow-diagnostics.png" style="height: 766px; width: 637px;"></p> + +<p>Grades go from A to F. Our page is just small and meets most criteria. But we can already note it would have been better to use a {{Glossary("CDN")}}. That doesn't matter very much when we're only serving one image, but it would be critical for a high-bandwidth website serving many thousands of images.</p> + +<h4 id="Is_the_server_responsive_enough">Is the server responsive enough?</h4> + +<p><code>ping</code> is a useful shell tool that tests the domain name you provide and tells you if the server's responding or not:</p> + +<pre>$ ping mozilla.org +PING mozilla.org (63.245.215.20): 56 data bytes +64 bytes from 63.245.215.20: icmp_seq=0 ttl=44 time=148.741 ms +64 bytes from 63.245.215.20: icmp_seq=1 ttl=44 time=148.541 ms +64 bytes from 63.245.215.20: icmp_seq=2 ttl=44 time=148.734 ms +64 bytes from 63.245.215.20: icmp_seq=3 ttl=44 time=147.857 ms +^C +--- mozilla.org ping statistics --- +4 packets transmitted, 4 packets received, 0.0% packet loss +round-trip min/avg/max/stddev = 147.857/148.468/148.741/0.362 ms</pre> + +<p>Just keep in mind a handy keyboard shortcut: <strong>Ctrl+C</strong>. Ctrl+C sends an “interrupt” signal to the runtime and tells it to stop. If you don't stop the runtime, <code>ping</code> will ping the server indefinitely.</p> + +<h3 id="A_simple_checklist">A simple checklist</h3> + +<ul> + <li>Check for 404s</li> + <li>Make sure all webpages are behaving as you expect</li> + <li>Check your website in several browsers to make sure it renders consistently</li> +</ul> + +<h2 id="Next_steps">Next steps</h2> + +<p>Congratulations, your website is up and running for anyone to visit. That's a huge achievement. Now, you can start digging deeper into various subjects.</p> + +<ul> + <li>Since people can come to your website from all over the world, you should consider making it <a href="/en-US/docs/Learn/What_is_accessibility">accessible to everybody</a>.</li> + <li>Is the design of your website a bit too rough? It's time to <a href="/en-US/docs/Learn/CSS/Using_CSS_in_a_web_page">learn more about CSS</a>.</li> +</ul> diff --git a/files/ko/learn/common_questions/코딩하기_전에_생각하기/index.html b/files/ko/learn/common_questions/코딩하기_전에_생각하기/index.html new file mode 100644 index 0000000000..8885c5999b --- /dev/null +++ b/files/ko/learn/common_questions/코딩하기_전에_생각하기/index.html @@ -0,0 +1,176 @@ +--- +title: 나의 웹사이트를 설계하기 위해서는? +slug: Learn/Common_questions/코딩하기_전에_생각하기 +tags: + - 능동학습필요 + - 초보자 +translation_of: Learn/Common_questions/Thinking_before_coding +--- +<p class="summary">이 글은 모든 프로젝트에서 중요한 첫 단계 - 프로젝트를 통해 달성하고 싶은 것을 정의하기 - 를 다룬다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">선이수:</th> + <td>없음</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>웹 프로젝트 방향 설정을 위해 목적을 정하는 법을 배운다.</td> + </tr> + </tbody> +</table> + +<h2 id="요약">요약</h2> + +<p><span class="seoSummary">웹 프로젝트를 시작할 때, 많은 사람들은 기술적인 면에 집중한다. 물론 자기 분야의 기술에 익숙해야한다. 그러나 </span>정말 중요한건 무엇을 달성하고 싶은가이다. 당연한 이야기같지만, 생각보다 많은 프로젝트들이 기술적 방법의 부족이 아닌, 목적과 전망의 부족으로 실패한다.</p> + +<p>따라서 아이디어를 얻고, 그것을 웹 사이트로 만들고 싶을 때, 다른 것보다 먼저 대답해야할 질문이 있다.</p> + +<ul> + <li>내가 달성하고 싶은 것은 정확히 무엇인가?</li> + <li>내 목적 달성을 웹사이트가 어떻게 돕는가?</li> + <li>목적 달성을 위해 무엇을, 어떤 순서로 해야할까?</li> +</ul> + +<p>이러한 것들을 프로젝트 관념(ideation)이라 한다. 당신이 초보자든 숙련된 개발자든 목표에 도달하기 위해 반드시 거쳐야 할 첫 단계이다.</p> + +<h2 id="능동_학습">능동 학습</h2> + +<p><em>아직 가능한 능동 학습이 없다. <a href="https://developer.mozilla.org/ko/docs/MDN/Getting_started">기여를 고민해보라</a>.</em></p> + +<h2 id="깊게_들어가기">깊게 들어가기</h2> + +<p>프로젝트는 절대 기술에서 시작하지 않는다. 음악가는 무엇을 연주할 지 정하기 전엔 어떤 음악도 만들지 않는다. 화가, 작가, 그리고 웹 개발자도 마찬가지다. 기술은 다음이다.</p> + +<p>기술은 분명히 중요하다. 음악가는 기악을 완성해야 한다. 그러나 좋은 음악가는 절대 생각없이 좋은 음악을 만들수 없다. 그러므로 코드와 툴같은 기술로 뛰어들기 전에, 한 걸음 물러서서 하고 싶은 것을 상세히 결정해야 한다.</p> + +<p>친구와 함께하는 한 시간의 토론은 좋은 시작이지만 부족하다. 생각을 현실로 만들 길의 탁 트인 전망을 얻으려면 앉아서 생각을 구조화해야한다. 이것을 하기 위해서, 오직 펜과 종이 그리고 적어도 다음 질문에 대한 답할 시간이 필요하다.</p> + +<div class="note"> +<p><strong>메모:</strong> 프로젝트 관념화를 수행하기 위한 셀 수 없는 방법들이 있다. 우리는 여기에 그것들을 모두 제시할 수는 없다. (책 전체로는 충분하지 않을 것이다). 이 곳에 주는 것은 전문가들이 <a href="http://en.wikipedia.org/wiki/Ideation_(idea_generation)">Project Ideation(관념화)</a>, <a href="http://en.wikipedia.org/wiki/Project_planning">Project Planning(계획)</a> 그리고 <a href="http://en.wikipedia.org/wiki/Project_management">Project Management(관리)</a> 라고 부르는 것을 다루는 단순한 방법이다.</p> +</div> + +<h3 id="내가_정확히_달성하고_싶은_것은_무엇인가">내가 정확히 달성하고 싶은 것은 무엇인가?</h3> + +<p>이것은 대답해야 하는 가장 중요한 질문이다. 왜냐하면, 이것이 다른 모든 것을 만들기 때문이다. 도달하고 싶은 모든 목표를 목록화해라. 그것은 무엇일 수도 있다: 돈을 벌기 위해 물건 팔기, 정치적인 의견 표현하기, 새로운 친구 만들기, 음악가들과 공연하기, 고양이 사진 모으기, 또는 원하는 무엇이든.</p> + +<p>당신이 음악가라고 생각해보자. 이런걸 원할 수 있다.</p> + +<ul> + <li>다른 사람들이 내 음악을 듣게 하기</li> + <li>관련 상품 팔기 </li> + <li>다른 음악가들과 만나기</li> + <li>내 음악에 대해 이야기하기</li> + <li>동영상으로 음악 가르치기</li> + <li>내 고양이 사진 출판하기</li> + <li>새로운 애인 찾기</li> +</ul> + +<p>일단 이런 리스트를 만들고 나면, 우선순위를 정하는 것이 필요하다. 가장 중요한 것부터 덜 중요한 것까지 목표를 정렬해라.</p> + +<ol> + <li>새로운 애인 찾기</li> + <li>다른 사람들이 내 음악을 듣게 하기</li> + <li>내 음악에 대해 이야기하기</li> + <li>다른 음악가들과 만나기</li> + <li>관련 상품 팔기 </li> + <li>동영상으로 음악 가르치기</li> + <li>내 고양이 사진 출판하기</li> +</ol> + +<p>단순한 목표 쓰기와 순위 정하기가 만들고 싶은 것을 결정할 때, 도움이 될 것이다. (내가 이런 특징을 구현해야할까, 이런 서비스를 사용해야할까, 이런 디자인을 만들어야할까?)</p> + +<p>우선순위가 정리된 목적 기록부가 생겼으니, 다음 질문으로 이동하자.</p> + +<h3 id="어떻게_웹사이트가_나를_목적지로_데려다_줄_수_있을까">어떻게 웹사이트가 나를 목적지로 데려다 줄 수 있을까?</h3> + +<p>그래서 당신은 목표 리스트를 가지고 있고, 그 목표들을 이루기위해 웹사이트가 필요하다고 느낍니다. 확실합니까?</p> + +<p>우리의 예를 다시 봅시다. 우리는 음악에 관련된 5개의 목표, 개인 삶(소중한 사람 찾기)에 관련된 하나의 목표 그리고, 완전히 상관없는 고양이 사진을 가지고 있습니다. 이 모든 목표들을 다루기 위한 하나의 웹사이트를 만드는 것이 합리적입니까? 그것이 필요할까요? 결국에, 많은 기존의 웹 서비스는 새로운 웹사이트를 만들지 않고 당신의 목표를 가져다 줄 지 모릅니다.</p> + +<p>애인을 찾는 것은 새로운 웹사이트를 구축하는 것보다 기존의 자원을 사용하는 것이 더 알맞다는 점에서 중요한 케이스입니다. 왜? 왜냐하면 우리가 실제로 애인을 찾는 것보다 웹사이트를 구축하고 유지하는 데 더 많은 시간을 소비하기 때문입니다. 우리의 목표가 가장 중요하기 때문에, 우리는 처음부터 시작하는 것보다는 기존의 툴을 레버리징(leveraging )하는 것에 에너지를 써야합니다. 다시, 사진을 보여주기 위해 이용할 수 있는 이미 너무 많은 웹서비스가 있습니다 그래서 우리의 고양이가 얼마나 귀여운 지에 대한 것을 퍼뜨리기 위해 새로운 사이트를 구축하는 데 노력할 가치가 없습니다.</p> + +<p>음악과 연관된 다른 5개의 목표가 있습니다. 물론, 이런 목표들을 다룰 수 있는 많은 웹서비스가 있습니다. 그러나, 우리만을 위한 웹사이트를 구축하는 경우에는 이해가 됩니다. 그런 웹사이트는 하나의 공간에 퍼블리싱하고 싶은 모든 항목을 합치는 것과 (목표 3, 5, 6에 적합) 그리고 우리와 대중 사이에 상호작용을 장려하는 것에 (목표 2, 4) 가장 좋은 방법입니다. 다시 말해서, 이런 목표들이 같은 주제를 중심으로 돌기 때문에, 한 곳에 모든 것을 가지는 것이 우리의 목표를 충족하고, 팔로어들과 연결하는 데 도움이 될 것입니다.</p> + +<p>어떻게 웹사이트가 나의 목표를 달성하는 데 도움이 될까요? 그것에 답함으로써, 우리는 우리의 목표를 달성하는 데 가장 좋은 방법을 찾을 것이고, 노력이 낭비되지 않도록 할 것입니다.</p> + +<h3 id="내_목표를_달성하기_위해_무엇을_어떤_순서로_해야할까">내 목표를 달성하기 위해, 무엇을, 어떤 순서로 해야할까?</h3> + +<p>이제 우리가 달성하고 싶은 것을 알고 있으므로, 그 목표들을 실행가능한 단계로 바꿀 시간입니다.</p> + +<p>긴 설명을 하기 보다는 이 표로 우리의 예제를 돌아봅시다:</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">목표</th> + <th scope="col">해야할 것</th> + </tr> + </thead> + <tbody> + <tr> + <td style="vertical-align: top;">사람들이 당신의 음악을 듣게 하기</td> + <td> + <ol> + <li>음악을 녹음한다.</li> + <li>온라인에서 사용할 수 있는 몇몇의 오디오 파일을 준비힌다. (기존의 웹서비스로 이것을 할 수 있을까?)</li> + <li>사람들에게 당신의 웹사이트의 일부에서 당신의 음악에 접근하게 한다.</li> + </ol> + </td> + </tr> + <tr> + <td style="vertical-align: top;">음악에 대해 이야기하기</td> + <td> + <ol> + <li>토의를 시작하기 위한 몇몇의 글을 쓴다.</li> + <li>어떻게 글이 보여야 하는 지 정해라.</li> + <li>웹사이트에 이 글을 게시해라 (어떻게 이것을 할까?)</li> + </ol> + </td> + </tr> + <tr> + <td style="vertical-align: top;">다른 음악가들 만나기</td> + <td> + <ol> + <li>사람들이 너와 연락할 방법을 제공해라.</li> + <li>너의 웹사이트에서 어떻게 사람들이 연락 채널을 찾을 지 정해라.</li> + </ol> + </td> + </tr> + <tr> + <td style="vertical-align: top;">goodies 팔기</td> + <td> + <ol> + <li>goodies 만든다.</li> + <li>goodies 저장한다.</li> + <li>쇼핑을 하는 방식 찾는다.</li> + <li>결제 방식 찾는다.</li> + <li>사이트에서 사람들의 주문 메카니즘 만든다.</li> + </ol> + </td> + </tr> + <tr> + <td style="vertical-align: top;">동영상을 통해 음악 가르치기</td> + <td> + <ol> + <li>동영상 강의 녹화한다.</li> + <li>온라인에서 볼 수 있는 동영상 파일 준비한다. (다시, 기존의 웹사이트에서 할 수 있을까?)</li> + <li>웹사이트의 한 부분에서 비디오 접근 가능하게 한다.</li> + </ol> + </td> + </tr> + </tbody> +</table> + +<p>공지할 것이 두 개가 있다. 첫째, 이런 아이템 중 몇몇은 웹과 상관이 없다. (예를 들어, 음악 녹음, 글 쓰기) 종종 그런 오프라인 활동이 프로젝트의 웹 부분보다 훨씬 더 중요하다. 예를 들어, 판매의 경우에, 공급, 결제, 배달에 시간을 쓰는 것이 사람들이 주문할 수 있는 웹사이트를 만드는 것보다 훨씬 더 중요하다.</p> + +<p>둘째, 실행가능한 단계를 설정하는 것은 우리가 답할 필요가 있는 새로운 질문을 이끌어 낸다. 종종 우리가 본래 생각했던 것보다 더 많은 질문으로 변한다. (예를 들어, 내가 혼자서 어떻게 이것을 배워야할까? 누군가에게 이것을 부탁할까? 서드파티(제 3의) 서비스를 사용해야할까?)</p> + +<h2 id="결론">결론</h2> + +<p>당신이 본 것 처럼, "나는 웹사이트를 만들고 싶다" 라는 단순한 생각이 긴 해야할 목록을 만들었다. 그리고 그것은 생각하면 할 수록 더 길어진다. 금방 그것은 압도적으로 보일 것이다. 그러나 겁먹지 마라. 당신은 모든 질문에 대답할 필요는 없다. 그리고 당신은 리스트에 모든 것을 할 필요는 없다. 중요한 것은 원하는 것과 도달하는 법에 대한 비전을 가지고 있어야하는 것이다. 일단 분명한 비전이 있다면, 당신은 해야할 때와 하는 방법을 결정할 필요가 있다. 큰 일을 작은 실행할 수 있는 단계로 부숴라. 그리고 그 작은 단계를 거대한 성과로 합쳐라.</p> + +<p>이 글에서, 당신은 웹사이트를 만들기 위한 개략적인 계획을 지금 세울 수 있어야 한다. 다음 단계는 <a href="https://developer.mozilla.org/en-US/docs/Learn/Common_questions/How_does_the_Internet_work">how the Internet works(인터넷이 작동하는 법)</a> 을 읽어야 할 것이다.</p> + +<p> </p> diff --git a/files/ko/learn/css/basics/layout/index.html b/files/ko/learn/css/basics/layout/index.html new file mode 100644 index 0000000000..50cfb20039 --- /dev/null +++ b/files/ko/learn/css/basics/layout/index.html @@ -0,0 +1,408 @@ +--- +title: Introduction to CSS Layout +slug: Learn/CSS/Basics/Layout +translation_of: Learn/CSS/CSS_layout/Introduction +--- +<p>{{PreviousNext("Learn/CSS/Basics/Box_model","Learn/CSS/Howto/style_text")}}</p> + +<p class="summary"><span class="seoSummary">CSS layout is the art of using various CSS properties to alter the positioning of elements on a document in order to fit the design requirements.</span> CSS provides many layout mechanisms, the more advanced and modern techniques are so complex that they get their own articles. In this article, we will introduce the basic techniques that have been used for years.</p> + +<p>To properly layout a document with CSS, there are a few notions that one must know. The most important of these is {{Glossary("HTML")}} text flow. We will cover it in this article. Articles about other layout mechanisms will, at some point or the other, refer back to what we are discussing here.</p> + +<h2 id="The_flow">The flow</h2> + +<p>At its most basic level an HTML document is a text document structured with {{Glossary("tag","tags")}}. In such a document, the text <em>flows</em>. That means text is displayed in the reading direction (from left to right, for example, in Latin based languages like English or French) and is broken automatically - creating new lines - each time the text reaches an edge of the document.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/11955/line-break-flow.svg" style="height: auto; max-width: 450px;"></p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/11955/line-break-flow.svg#large" style="height: auto; max-width: 450px;"></p> + +<p>Each {{Glossary("element","elements")}} in the document alters the flow of text in various ways:</p> + +<ul> + <li>Some elements can simply follow the text flow as if they were non-existent.</li> + <li>Some elements can force a line break at any point in the flow whether it has reached the edge of the document or not.</li> + <li>Some elements can create a new text flow for their inner content independent from the main text flow.</li> +</ul> + +<h3 id="디스플레이_요소_(Elements_display_categories)">디스플레이 요소 (Elements display categories)</h3> + +<p>CSS is used to define how an HTML element behaves within the flow and how it get in and out of that flow. The element behavior is defined using the property {{cssxref('display')}}. This property can take tons of values but let's focus on the four most important:</p> + +<dl> + <dt>none</dt> + <dd>모든 요소를 제거 합니다.</dd> + <dt>inline</dt> + <dd>줄을 바꾸지 않고, 해당 위치에서 다른 요소들과 같은 선상에 위치하려는 성질을 말합니다. </dd> + <dt>block</dt> + <dd>This value is for the element to break the text flow with a forced line break before and after it. Its content is no longer part of the global text flow and flows only within the constraints provided by the element <a href="/en-US/docs/Learn/CSS/Basics/Box_model">box model</a>.</dd> + <dt>inline-block</dt> + <dd>This value makes the element somewhat in between inline and block type display: like <code>inline</code> boxes it flows with the text normally but, like block boxes, it's content is no longer part of the global text.</dd> +</dl> + +<p>Let's see an example.</p> + +<p>HTML:</p> + +<pre class="brush: html"><p class="none"> + 1. I'm a big black cat, + <span>walking under a ladder,</span> + and I can see broken mirrors everywhere. +</p> + +<p class="inline"> + 2. I'm a big black cat, + <span>walking under a ladder,</span> + and I can see broken mirrors everywhere. +</p> + +<p class="block"> + 3. I'm a big black cat, + <span>walking under a ladder,</span> + and I can see broken mirrors everywhere. +</p> + +<p class="inline-block"> + 4. I'm a big black cat, + <span>walking under a ladder,</span> + and I can see broken mirrors everywhere. +</p> +</pre> + +<p>CSS:</p> + +<pre class="brush: css">span { + width: 5em; + background: yellow; +} + +.none span { display: none; } +.inline span { display: inline; } +.block span { display: block; } +.inline-block span { display: inline-block; }</pre> + +<p>Results:</p> + +<p>{{EmbedLiveSample('Elements_display_categories', '100%', '300px')}}</p> + +<h2 id="Altering_the_flow">Altering the flow</h2> + +<p>By setting the display property you're already altering the flow, but you can go further.</p> + +<h3 id="Text_layout">Text layout</h3> + +<p>While an HTML document is nothing more than a long text flow, CSS provides many properties to deal with simple text layout. The text layout is everything that allows changing the text line breaking rules and the way the text is positioned over the natural text line.</p> + +<p>Those properties are: {{cssxref("hyphens")}}, {{cssxref("text-align")}}, {{cssxref("text-align-last")}}, {{cssxref("text-indent")}}, {{cssxref("vertical-align")}}, {{cssxref("white-space")}}, {{cssxref("word-break")}}, and {{cssxref("word-wrap")}}.</p> + +<p>Except for <code>text-align and<font face="Open Sans, Arial, sans-serif">, </font></code><code>text-indent </code>the other properties have subtle effects on the text and <code>vertical-align</code> is often used with inline-block boxes.</p> + +<p>An example will make things clearer.</p> + +<p>HTML:</p> + +<pre class="brush: html"><p lang="en">WHEN Scrooge awoke, it was so dark, that looking out of bed, he could scarcely distinguish the transparent window from the opaque walls of his chamber. He was endeavouring to pierce the darkness with his ferret eyes, when the chimes of a neighbouring church struck the four quarters. So he listened for the hour. To his great astonishment the heavy bell went on from six to seven, and from seven to eight, and regularly up to twelve; then stopped. Twelve! It was past two when he went to bed. The clock was wrong. An icicle must have got into the works. Twelve! He touched the spring of his repeater, to correct this most preposterous clock. Its rapid little pulse beat twelve: and stopped.</p> +<p class="format" lang="en">WHEN Scrooge awoke, it was so dark, that looking out of bed, he could scarcely distinguish the transparent window from the opaque walls of his chamber. He was endeavouring to pierce the darkness with his ferret eyes, when the chimes of a neighbouring church struck the four quarters. So he listened for the hour. To his great astonishment the heavy bell went on from six to seven, and from seven to eight, and regularly up to twelve; then stopped. Twelve! It was past two when he went to bed. The clock was wrong. An icicle must have got into the works. Twelve! He touched the spring of his repeater, to correct this most preposterous clock. Its rapid little pulse beat twelve: and stopped.</p> +</pre> + +<p>CSS:</p> + +<pre class="brush: css">.format { + /* The first line is "pull" to a 2em distance */ + text-indent: -2em; + + /* We need to compensate the negative indent + to avoid unwanted text clipping and keep + the whole text within the boundary of its + element box */ + padding-left: 2em; + + /* The text is aligned on both edges, adjusting + spacing between words as necessary */ + text-align: justify; + + /* The last line of the block of text is centered */ + -moz-text-align-last: center; + text-align-last: center; + + /* Rather than line break between two words the line + break can occur inside words, according to the rules + defined for the text language. This makes nice word cut + with a clear hyphen dash. If you don care about word + breaking rules, you could just use word-break or + word-wrap instead */ + -webkit-hyphens: auto; + -moz-hyphens: auto; + -ms-hyphens: auto; + hyphens: auto; +}</pre> + +<div class="note"> +<p>As you might notice, some properties are written multiple times with some prefix. This is because those prefixed properties are still experimental for some browsers and it is considered best practice to use them all with the standard property at the end of the list in order to provide the best backward compatibility possible.</p> +</div> + +<p>Results:</p> + +<p>{{ EmbedLiveSample('Text_layout', '100%', '350') }}</p> + +<div class="note"> +<p>It's worth noting that the trick we used to compensate the negative text indentation is a very common trick. Any property that accepts a length also accepts negative values. By fiddling with negative values and compensating them with other properties, it's possible to produce very clever effects on the layout, especially when it applies to properties of the box model.</p> +</div> + +<h3 id="Floating">Floating</h3> + +<p>Okay, handling text is nice, but at some point what we really want is to move boxes around the document. The first way to handle that is to deal with floating boxes. Floating boxes are still attached to the global text flow, but the text will flow around. Sounds weird, so let's see an example.</p> + +<h4 id="Simple_floating">Simple floating</h4> + +<p>HTML:</p> + +<pre class="brush: html"><div> + <p class="excerpt">"Why, it isn't possible," said Scrooge, "that I can have slept through a whole day and far into another night. It isn't possible that anything has happened to the sun, and this is twelve at noon!" </p> + <p> The idea being an alarming one, he scrambled out of bed, and groped his way to the window. He was obliged to rub the frost off with the sleeve of his dressing-gown before he could see anything; and could see very little then. All he could make out was, that it was still very foggy and extremely cold, and that there was no noise of people running to and fro, and making a great stir, as there unquestionably would have been if night had beaten off bright day, and taken possession of the world. This was a great relief, because "three days after sight of this First of Exchange pay to Mr. Ebenezer Scrooge or his order," and so forth, would have become a mere United States' security if there were no days to count by.</p> +</div></pre> + +<p>CSS:</p> + +<pre class="brush: css">.excerpt { + /* A floating box will act like a block whatever + the value of display we are using */ + display: block; + + /* Our box is floating to the left, which means + it will stack on the left side of the containing + block and the text will flow on its right side. */ + float: left; + + /* It is required to set a width to a floating box. + If we don't its width will be set + automatically, which means that it will grow as much + as possible and nothing will flow around it, like an + ordinary block box */ + width: 40%; + + /* We set some margins on the right and bottom side of + the box to avoid having the text flowing around being + in direct visual contact of our floating box */ + margin: 0 1em 1em 0; + + /* We make our floating box more visible with + a simple background color */ + background: lightgrey; + + /* As we have a solid background color it's a nice idea + to push the content a little bit away from the edges + of the box */ + padding: 1em; +}</pre> + +<p>Results:</p> + +<p>{{ EmbedLiveSample('Simple_floating', '100%', '280') }}</p> + +<h4 id="Layout_with_floating">Layout with floating</h4> + +<p>This is a very simple effect to start tweaking the flow to our wishes. Now it's possible to do better and start performing some true layout. A floating box that floats in a given direction stacks horizontally, it's a very convenient way to create rows of boxes instead of natural columns: In the flow, block boxes stack in columns and floating boxes stack in rows.</p> + +<p>Once again, an example will make things clearer.</p> + +<p>HTML:</p> + +<pre class="brush: html"><div class="layout"> + <div class="row"> + <p class="cell size50">Scrooge went to bed again, and thought, and thought, and thought it over and over and over, and could make nothing of it. The more he thought, the more perplexed he was; and the more he endeavoured not to think, the more he thought.</p> + <p class="cell size50">Marley's Ghost bothered him exceedingly. Every time he resolved within himself, after mature inquiry, that it was all a dream, his mind flew back again, like a strong spring released, to its first position, and presented the same problem to be worked all through, "Was it a dream or not?"</p> + </div> + <div class="row"> + <p class="cell size100">Scrooge lay in this state until the chime had gone three quarters more, when he remembered, on a sudden, that the Ghost had warned him of a visitation when the bell tolled one. He resolved to lie awake until the hour was passed; and, considering that he could no more go to sleep than go to Heaven, this was perhaps the wisest resolution in his power.</p> + </div> + <div class="row"> + <p class="cell size33">The quarter was so long, that he was more than once convinced he must have sunk into a doze unconsciously, and missed the clock. At length it broke upon his listening ear.</p> + <p class="cell size33"> + "Ding, dong!"<br> + "A quarter past," said Scrooge, counting.<br> + "Ding, dong!"<br> + "Half-past!" said Scrooge.<br> + "Ding, dong!"<br> + "A quarter to it," said Scrooge.<br> + "Ding, dong!"<br> + "The hour itself," said Scrooge, triumphantly, "and nothing else!" + </p> + <p class="cell size33"> + He spoke before the hour bell sounded, which it now did with a deep, dull, hollow, melancholy ONE. Light flashed up in the room upon the instant, and the curtains of his bed were drawn. + </p> + </div> +</div></pre> + +<p>CSS:</p> + +<pre class="brush: css">/* This is our main layout container */ +.layout { + /* A background makes it visible */ + background: lightgrey; + + /* We add a small visual spacing to harmonize + the distance between the cells content and + and the layout border */ + padding : 0.5em; +} + +/* A floating box gets somewhat out of + the flow, so if their container is empty + it will have a zero height size and the + floating box will overflow it. To + avoid such a situation, we make sure floating + boxes are not allowed to overflow. In + that specific context, with an overflow + hidden, floating boxes won't be clipped, + the parent box will extend to avoid any + floating box overflow. */ +.row { + overflow: hidden; +} + +/* Each cell is a left floating box */ +.cell { + float : left; + + /* we add padding to our cell to create + some nice visual gutters between them */ + padding : 0.5em; + + /* Because we are adding padding, we need + to be sure that it will not impact + the box width. */ + box-sizing: border-box; + + /* As margins cannot be controlled with the + box-sizing property, we need to be sure + there is none applied to our cell. */ + margin : 0; +} + +/* Those are the sizes we can apply to our boxes */ +.size33 { width: 33%; } /* Not exactly a third, but good enough */ +.size50 { width: 50%; } /* A half */ +.size100 { width: 100%; } /* A full row */</pre> + +<p>Results:</p> + +<p>{{ EmbedLiveSample('Layout_with_floating', '100%', '520') }}</p> + +<p>Using floating boxes this way, is what many CSS frameworks do. It's a robust and well-known technique but it has limits as everything must go with the flow: it's not possible to handle boxes in arbitrary order, variable sizing can be quite tricky to achieve, and vertical centering is impossible. We encourage you to dig deeper as <a href="http://www.positioniseverything.net/articles/onetruelayout/">floating boxes has been studied for long</a> and they are among the most robust solutions for a simple layout that must be compatible with legacy browsers.</p> + +<p>If you want to better understand all the subtleties of floating boxes, we encourage you to read <em><a href="https://css-tricks.com/all-about-floats/">All about float</a></em> by Chris Coyer.</p> + +<h3 id="Positioning">Positioning</h3> + +<p>If floating boxes are still part of the flow, another mechanism exists to perform some layouts by extracting boxes out of the flow: CSS Positioning. Positioning is acheived by defining a positioning context with the {{cssxref("position")}} property and then allows boxes to be positioned using {{cssxref("top")}}, {{cssxref("left")}}, {{cssxref("right")}}, and {{cssxref("bottom")}} properties.</p> + +<p>The {{cssxref("position")}} property can take on four different values:</p> + +<dl> + <dt>static</dt> + <dd>This is the default value for all elements: they are part of the flow and don't define any specific positioning context.</dd> + <dt>relative</dt> + <dd>With this value, elements are still part of the flow, but they can be visually moved around their positions with {{cssxref("top")}}, {{cssxref("left")}}, {{cssxref("right")}}, and {{cssxref("bottom")}}. They also define a positioning context for their children elements.</dd> + <dt>absolute</dt> + <dd>With this value, elements are pushed out of the flow and no longer influence it. The position of such blocks is defined by the {{cssxref("top")}}, {{cssxref("left")}}, {{cssxref("right")}}, and {{cssxref("bottom")}} properties. The 0,0 position point for the top/left corner of the box is the top/left corner of the closest parent element which defines a positionning context other than <em>static</em>. If there is no parent with a positioning context, then, the 0,0 position point for the top/left corner of the box is the top/left corner of the document.</dd> + <dt>fixed</dt> + <dd>With this value, elements are pushed out of the flow and no longer influence it. The position of such blocks is define by the {{cssxref("top")}}, {{cssxref("left")}}, {{cssxref("right")}}, and {{cssxref("bottom")}} properties. The 0,0 position point for the top/left corner of the box is the top/left corner of the browser window {{Glossary("viewport")}}.</dd> +</dl> + +<p>Such positioned boxes can stack on top of each other. In that case, it's possible to change the stacking order by using the {{cssxref("z-index")}} property.</p> + +<p>Okay, let's see an example to visualize it at work.</p> + +<p>HTML:</p> + +<pre class="brush: html"><div class="relative"> + <div class="absolute-one"> + <p>Position:absolute</p></br> + <p>Top Right</p> + </div> + + <div class="absolute-two"> + <p>Position:absolute</p></br> + <p>Bottom Centre</p> + </div> + + <div class="absolute-three"> + <p>Position:static</p></br> + <p>Where it falls</p> + </div> +</div></pre> + +<p>CSS:</p> + +<pre class="brush: css">p { + text-align: centre; + color: #fff; +} + + +/* Setting the position to relative +allows any child elements to be positioned +anywhere, in <em><strong>relation</strong> to its container. */ +</em> +.relative { + position: relative; + width: 95%; + margin: 0 auto; + height: 300px; + background-color: #fff; + border: 3px solid #ADD8E6; +} + +/* Just some styles for text alignment /* +.relative div { + text-align: center; + padding: 5px; + display: block; + width: 125px; + height: 125px; + background-color: #ADD8E6; +} + +/* By setting this div to position absolute +we can position this element anywhere in relation +to the 'relative' div /* +.absolute-one { + position: absolute; + top: 0; + right: 0; +} + +/* Unlike the first div which was positioned at the +top right corner of the container div. '.absolute-two' +is positioned bottom centre. By setting both left and right +to 0, along with margin:auto. +.absolute-two { + position: absolute; + bottom: 0; + right: 0; + left: 0; + margin: auto; +} + +/* Where the div would fall naturally within it's container. +This is also useful for returning elements from a floated +position. E.g. on responsive styles. /* +.absolute-three { + position: static; +} +</pre> + +<p>Results:</p> + +<p>{{ EmbedLiveSample('Positioning', '100%', '400') }}</p> + +<p>If CSS positioning isn't really used for full layout, it is used quite often to deal with trick UX effect such as navigation layout, tooltip and such. This is something you'll see on a regular basis so we encourage you to get into it. Among various resources about it, we suggest you take a look at the article <em><a href="http://alistapart.com/article/css-positioning-101">CSS positioning 101</a></em> by Noah Stokes.</p> + +<h2 id="What's_next">What's next</h2> + +<p>The flow, the floating boxes, and CSS positioning are the basic CSS knowledge that will drive you into CSS layout. Now you are ready to use CSS to its full potential! You should now take some time looking at <a href="/en-US/docs/Learn/CSS/Howto">practical usage of CSS</a>. If you want to dig even deeper into layouts, you should definitely take a look at the other layout mechanism that exists with CSS: Table display, <a href="/en-US/docs/Web/CSS/CSS_Columns/Using_multi-column_layouts">multiple columns layout</a>, and <a href="/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Using_CSS_flexible_boxes">flexible box layout</a>.</p> + +<p>{{PreviousNext("Learn/CSS/Basics/Box_model","Learn/CSS/Howto/style_text")}}</p> + +<div class="grammarly-disable-indicator"> </div> diff --git a/files/ko/learn/css/building_blocks/backgrounds_and_borders/index.html b/files/ko/learn/css/building_blocks/backgrounds_and_borders/index.html new file mode 100644 index 0000000000..a5e2983ea7 --- /dev/null +++ b/files/ko/learn/css/building_blocks/backgrounds_and_borders/index.html @@ -0,0 +1,318 @@ +--- +title: 배경 및 테두리 +slug: Learn/CSS/Building_blocks/Backgrounds_and_borders +translation_of: Learn/CSS/Building_blocks/Backgrounds_and_borders +--- +<div>{{LearnSidebar}}{{PreviousMenuNext("Learn/CSS/Building_blocks/The_box_model", "Learn/CSS/Building_blocks/Handling_different_text_directions", "Learn/CSS/Building_blocks")}}</div> + +<p>이번 수업에서는 CSS 배경과 테두리로 할 수 있는 창의적인 작업을 살펴보겠습니다. 그라데이션 (gradients), 배경 이미지, 둥근 테두리를 추가하는 것에서 배경과 테두리는 CSS 의 많은 스타일 질문에 대한 답입니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">전제조건:</th> + <td>기본 컴퓨터 활용 능력, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Installing_basic_software">기본 소프트웨어 설치</a>, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Dealing_with_files">파일 작업</a> 에 대한 기본 지식, HTML 기본 사항 (<a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">HTML 소개</a> 학습) 및 , CSS 작동 방식 이해 (<a href="/en-US/docs/Learn/CSS/First_steps">CSS 첫 번째 단계</a> 학습)</td> + </tr> + <tr> + <th scope="row">목적:</th> + <td>박스의 배경과 테두리 스타일을 지정하는 방법 배우기.</td> + </tr> + </tbody> +</table> + +<h2 id="CSS_의_스타일링_배경">CSS 의 스타일링 배경</h2> + +<p>CSS {{cssxref("background")}} 속성은 이 수업에서 만나게 될 많은 background longhand 속성의 줄임말 입니다. 스타일 시트에서 복잡한 배경 속성을 발견하면, 한 번에 많은 값을 전달할 수 있으므로 이해하기 어려울 수 있습니다.</p> + +<pre class="brush: css"><code>.box { + background: linear-gradient(105deg, rgba(255,255,255,.2) 39%, rgba(51,56,57,1) 96%) center center / 400px 200px no-repeat, + url(big-star.png) center no-repeat, rebeccapurple; +} </code> +</pre> + +<p>이 자습서의 뒷부분에서 속기 (shorthand) 작동 방식으로 돌아가지만, 먼저 개별 배경 속성을 보고, CSS 에서 배경으로 수행할 수 있는 다양한 작업을 살펴보겠습니다.</p> + +<h3 id="배경_색상">배경 색상</h3> + +<p>{{cssxref("background-color")}} 속성은 CSS 의 모든 요소에 대한 배경색을 정의합니다. 이 속성은 유효한 <code><a href="/en-US/docs/Web/CSS/color_value"><color></a></code> 를 허용합니다. <code>background-color</code> 는 요소의 내용 및 패딩 박스 아래로 확장됩니다.</p> + +<p>아래 예에서는 다양한 색상 값을 사용하여 박스, 제목 및 {{htmlelement("span")}} 요소에 배경색을 추가했습니다.</p> + +<p><strong>사용 가능한 <a href="/en-US/docs/Web/CSS/color_value"><color></a> 값을 사용하여, 이것들을 가지고 놀아보십시오.</strong></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/backgrounds-borders/color.html", '100%', 800)}}</p> + +<h3 id="배경_이미지">배경 이미지</h3> + +<p>{{cssxref("background-image")}} 속성을 사용하면 요소의 배경에 이미지를 표시할 수 있습니다. 아래 예에는 두 개의 박스가 있습니다 — 하나는 박스보다 큰 배경 이미지이고 다른 하나는 별 모양의 작은 이미지 입니다.</p> + +<p>이 예제는 배경 이미지에 대한 두 가지를 보여줍니다. 기본적으로 큰 이미지는 박스에 맞게 축소되지 않으므로 작은 이미지만 표시되는 반면, 작은 이미지는 박스를 채우기 위해 바둑판 식으로 배열됩니다. 이 경우 실제 이미지는 단일 별 입니다.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/backgrounds-borders/background-image.html", '100%', 800)}}</p> + +<p><strong>배경 이미지 외에 배경색을 지정하면 이미지가 색상 위에 표시됩니다. 위 예제에 <code>background-color</code> 속성을 추가하여 실제 상태를 확인하십시오.</strong></p> + +<h4 id="배경_이미지_반복_제어">배경 이미지 반복 제어</h4> + +<p>{{cssxref("background-repeat")}} 속성은 이미지의 타일링 동작을 제어하는 데 사용됩니다. 사용 가능한 값은 다음과 같습니다:</p> + +<ul> + <li><code>no-repeat</code> — 배경이 반복되지 않도록 합니다.</li> + <li><code>repeat-x</code> — 수평으로 반복합니다.</li> + <li><code>repeat-y</code> — 수직으로 반복합니다.</li> + <li><code>repeat</code> — 기본값; 양방향으로 반복합니다.</li> +</ul> + +<p><strong>아래 예에서 이러한 값을 사용해 보십시오. 값이 <code>no-repeat</code> 로 설정되어 별 하나만 표시됩니다. 다른 값 — <code>repeat-x</code> 및 <code>repeat-y</code> — 를 사용하여 그 효과가 무엇인지 확인하십시오.</strong></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/backgrounds-borders/repeat.html", '100%', 800)}}</p> + +<h4 id="배경_이미지_크기_조정">배경 이미지 크기 조정</h4> + +<p>위의 예에서 배경의 요소보다 커서, 이미지가 크게 잘립니다. 이 경우 <a href="/en-US/docs/Web/CSS/length">길이</a> 나 <a href="/en-US/docs/Web/CSS/percentage">백분율</a> 값을 취할 수 있는 {{cssxref("background-size")}} 속성을 사용하여 이미지 크기를 배경 안에 맞출 수 있습니다.</p> + +<p>키워드를 사용할 수도 있습니다:</p> + +<ul> + <li><code>cover</code> — 브라우저는 이미지를 박스 면적을 완전히 덮으면서 가로 세로 비율을 유지하며 이미지를 충분히 크게 만듭니다. 이 경우 일부 이미지가 박스 외부에 있을 수 있습니다.</li> + <li><code>contain</code> — 브라우저는 이미지를 박스 안에 들어가기에 적합한 크기로 만듭니다. 이 경우 이미지의 종횡비가 박스의 종횡비와 다른 경우, 이미지의 한쪽 또는 위쪽과 아래쪽에 간격이 생길 수 있습니다.</li> +</ul> + +<p>아래 예제에서는 위 예제의 큰 이미지를 사용했으며, 박스 안에 길이 단위를 사용하여 크기를 조정했습니다. 이미지가 왜곡된 것을 볼 수 있습니다.</p> + +<p>다음을 시도해 보십시오.</p> + +<ul> + <li>배경 크기를 수정하는 데 사용되는 길이 단위를 변경 하십시오.</li> + <li>길이 단위를 제거하고 <code>background-size: cover</code> 또는 <code>background-size: contain</code> 을 사용할 때 어떻게 되는지 확인 하십시오.</li> + <li>이미지가 박스보다 작으면, <code>background-repeat</code> 의 값을 변경하여 이미지를 반복할 수 있습니다.</li> +</ul> + +<p>{{EmbedGHLiveSample("css-examples/learn/backgrounds-borders/size.html", '100%', 800)}}</p> + +<h4 id="배경_이미지_배치">배경 이미지 배치</h4> + +<p>{{cssxref("background-position")}} 속성을 사용하면 적용되는 박스에서 배경 이미지가 나타나는 위치를 선택할 수 있습니다. 박스의 왼쪽 상단 모서리가 <code>(0,0)</code> 이고, 박스가 가로 (<code>x</code>) 및 세로 (<code>y</code>) 축을 따라 위치하는 좌표계를 사용합니다.</p> + +<div class="blockIndicator note"> +<p><strong>참고</strong>: <code>background-position</code> 의 기본값은 <code>(0,0)</code> 입니다.</p> +</div> + +<p>가장 일반적인 <code>background-position</code> 값은 — 수평 값과 수직 값의 두 가지 개별 값을 갖습니다.</p> + +<p><code>top</code> 및 <code>right</code> ({{cssxref("background-image")}} 페이지에서 다른 키워드를 찾으십시오) 와 같은 키워드를 사용 할 수 있습니다:</p> + +<pre class="brush: css"><code>.box { + background-image: url(star.png); + background-repeat: no-repeat; + background-position: top center; +} </code> +</pre> + +<p>그리고 <a href="/en-US/docs/Web/CSS/length">길이</a> 및 <a href="/en-US/docs/Web/CSS/percentage">백분율</a>:</p> + +<pre class="brush: css"><code>.box { + background-image: url(star.png); + background-repeat: no-repeat; + background-position: 20px 10%; +} </code> +</pre> + +<p>키워드 값을 길이 또는 백분율과 혼합할 수도 있습니다. 예를 들면:</p> + +<pre class="brush: css">.box { + background-image: url(star.png); + background-repeat: no-repeat; + background-position: top 20px; +}</pre> + +<p>마지막으로, 박스의 특정 모서리로 부터의 거리를 나타내기 위해 4 값 구문을 사용할 수도 있습니다 — 이 경우 길이 단위는 앞에 오는 값과의 offset 입니다. 아래 CSS 에서 우리는 배경을 위쪽에서 20px, 오른쪽에서 10px 로 배치합니다:</p> + +<pre class="brush: css"><code>.box { + background-image: url(star.png); + background-repeat: no-repeat; + background-position: top 20px right 10px; +} </code></pre> + +<p><strong>아래 예제를 사용하여 이러한 값을 가지고 실습하면서 박스 안에서 별을 움직이십시오.</strong></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/backgrounds-borders/position.html", '100%', 800)}}</p> + +<div class="blockIndicator note"> +<p><strong>참고</strong>: <code>background-position</code> 은 {{cssxref("background-position-x")}} 및 {{cssxref("background-position-y")}} 의 줄임말로, 다른 축 위치 값을 개별적으로 설정할 수 있습니다.</p> +</div> + +<h3 id="그라데이션_Gradient_배경">그라데이션 (Gradient) 배경</h3> + +<p>배경에 사용될 때 — Gradient — 는 이미지 처럼 작동하며 {{cssxref("background-image")}} 속성을 사용하여 설정 됩니다.</p> + +<p><code><a href="/en-US/docs/Web/CSS/gradient"><gradient></a></code> 데이터 유형에 대한 MDN 페이지에서 다양한 유형의 그라디언트 및 그라디언트로 수행 할 수 있는 작업에 대한 자세한 내용을 읽을 수 있습니다. 그라디언트를 재생하는 재미있는 방법은 웹에서 사용할 수 있는 많은 CSS 그라디언트 생성기 중 <a href="https://cssgradient.io/">하나</a> 를 사용하는 것입니다. 그라디언트를 생성한 다음 이를 생성하는 소스 코드를 복사하여 붙여 넣을 수 있습니다.</p> + +<p>아래 예제에서 다른 그라디언트를 사용해 보십시오. 두 개의 박스에는 각각 전체 박스에 걸쳐 펼쳐지는 선형 그라디언트와 설정된 크기의 방사형 그라디언트가 있습니다. 따라서 반복됩니다.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/backgrounds-borders/gradients.html", '100%', 800)}}</p> + +<h3 id="여러_배경_이미지">여러 배경 이미지</h3> + +<p>여러 개의 배경 이미지를 가질 수도 있습니다 — 하나의 속성 값으로 여러 개의 <code>background-image</code> 값을 지정하고, 각 이미지를 쉼표로 구분합니다.</p> + +<p>이렇게 하면 배경 이미지가 서로 겹칠 수 있습니다. 배경은 stack 맨 아래에 마지막으로 나열된 배경 이미지와 함께 쌓이고, 코드에서 그 뒤에 오는 이미지 위에 각각의 이전 이미지가 쌓입니다.</p> + +<div class="blockIndicator note"> +<p><strong>참고</strong>: 그라디언트는 일반 배경 이미지와 혼합될 수 있습니다.</p> +</div> + +<p>다른 <code>background-*</code> 속성은 <code>background-image</code> 와 같은 방식으로 쉼표로 구분된 값을 가질 수도 있습니다:</p> + +<pre class="brush: css">background-image: url(image1.png), url(image2.png), url(image3.png), url(image1.png); +background-repeat: no-repeat, repeat-x, repeat; +background-position: 10px 20px, top right;</pre> + +<p>다른 속성의 각 값은 다른 속성의 같은 위치에 있는 값과 일치합니다. 예를 들어, <code>image1</code> 의 <code>background-repeat</code> 값은 <code>no-repeat</code> 입니다. 그러나, 다른 속성의 값이 다른 경우 어떻게 됩니까? 답은 더 적은 수의 값이 순환한다는 것입니다 — 위의 예에서는 4 개의 배경 이미지가 있지만 2 개의 <code>background-position</code> 값만 있습니다. 처음 두 위치 값은 처음 두 이미지에 적용되고 다시 순환됩니다 — <code>image3</code> 에는 첫 번째 위치값이 제공되고, <code>image4</code> 에는 두 번째 위치값이 제공됩니다.</p> + +<p><strong>해봅시다. 아래 예에서는 두 개의 이미지를 포함했습니다. 쌓인 순서를 설명하려면, 목록에서 어떤 배경 이미지가 먼저 나오는지 전환해 보십시오. 또는 다른 속성을 사용하여 위치, 크기 또는 반복 값을 변경하십시오.</strong></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/backgrounds-borders/multiple-background-image.html", '100%', 800)}}</p> + +<h3 id="배경_첨부_attachment">배경 첨부 (attachment)</h3> + +<p>배경에 사용할 수 있는 또 다른 옵션은 내용이 스크롤될 때 스크롤하는 방법을 지정하는 것입니다. 이는 {{cssxref("background-attachment")}} 속성을 사용하여 제어되며, 다음 값을 사용할 수 있습니다:</p> + +<ul> + <li><code>scroll</code>: 페이지가 스크롤될 때 요소의 배경이 스크롤 되도록 합니다. 요소 내용이 스크롤되면, 배경이 움직이지 않습니다. 실제로 배경은 페이지에서 동일한 위치로 고정되므로, 페이지가 스크롤될 때 스크롤 됩니다.</li> + <li><code>fixed</code>: 요소의 배경을 viewport 에 고정시켜, 페이지나 요소 내용을 스크롤할 때 스크롤되지 않도록 합니다. 항상 화면에서 동일한 위치에 유지됩니다.</li> + <li><code>local</code>: 이 값은 나중에 추가 되었습니다 (Explorer 9 이상에서만 지원되지만, 다른 값은 IE4 이상에서 지원됨). 왜냐하면 <code>scroll</code> 값이 다소 혼란스럽고 많은 경우 실제로 원하는 것을 수행하지 않기 때문입니다. <code>local</code> 값은 배경을 설정된 요소로 고정하므로, 요소를 스크롤하면 배경과 함께 스크롤 됩니다.</li> +</ul> + +<p>{{cssxref("background-attachment")}} 속성은 스크롤할 내용이 있을 때만 영향을 미치므로, 세 가지 값의 차이점을 보여주는 데모를 만들었습니다 — <a href="http://mdn.github.io/learning-area/css/styling-boxes/backgrounds/background-attachment.html">background-attachment.html</a> 을 살펴보십시오 (여기에서 <a href="https://github.com/mdn/learning-area/tree/master/css/styling-boxes/backgrounds">소스 코드</a> 를 참조하십시오).</p> + +<h3 id="배경_속기_shorthand_속성_사용">배경 속기 (shorthand) 속성 사용</h3> + +<p>이 수업 시작 부분에서 언급했듯이, {{cssxref("background")}} 속성을 사용하여 지정된 배경을 자주 볼 수 있습니다. 이 속기 기능을 사용하면 모든 다른 속성을 한 번에 설정할 수 있습니다.</p> + +<p>여러 배경을 사용하는 경우, 첫 번째 배경에 대한 모든 속성을 지정한 다음, 쉼표 뒤에 다음 배경을 추가해야 합니다. 아래 예에서는 크기와 위치가 있는 그라디언트, <code>no-repeat</code> 및 이미지 위치가 있는 이미지 배경, 색상이 있습니다.</p> + +<p>배경 이미지 속기 값을 쓸 때 따라야 할 몇 가지 규칙이 있습니다. 예를 들면:</p> + +<ul> + <li><code>background-color</code> 는 마지막 쉼표 뒤에만 지정할 수 있습니다.</li> + <li><code>background-size</code> 의 값은 <code>background-position</code>, 직후에 포함되며 <code>center/80%</code> 와 같이 '/' 문자로 구분됩니다.</li> +</ul> + +<p>모든 고려 사항을 보려면 MDN 페이지의 {{cssxref("background")}} 를 살펴보십시오.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/backgrounds-borders/background.html", '100%', 800)}}</p> + +<h3 id="배경이_있는_접근성_고려_사항">배경이 있는 접근성 고려 사항</h3> + +<p>배경 이미지나 색상 위에 텍스트를 배치 할 때, 방문자가 텍스트를 읽을 수 있도록 contrast 를 충분히 유지해야 합니다. 이미지를 지정하고 해당 이미지 위에 텍스트를 배치하는 경우, 이미지가 로드되지 않은 경우 텍스트를 읽을 수 있는 <code>background-color</code> 도 지정해야 합니다.</p> + +<p>화면 판독기는 배경 이미지를 구문 분석할 수 없으므로 순전히 장식이어야 합니다. 중요한 내용은 HTML 페이지의 일부여야 하며, 배경에 포함되지 않아야 합니다.</p> + +<h2 id="테두리">테두리</h2> + +<p>박스 모델에 대해 알아볼 때, 테두리가 박스 크기에 어떤 영향을 미치는지 알아 냈습니다. 이 수업에서는 테두리를 창의적으로 사용하는 방법을 살펴봅니다. 일반적으로 CSS 를 사용하여 요소에 테두리를 추가할 때는, CSS 의 한 라인에 테두리의 색상, 너비 및 스타일을 설정하는 속기 속성을 사용합니다.</p> + +<p>{{cssxref("border")}} 를 사용하여 박스의 네 면 모두에 테두리를 설정할 수 있습니다:</p> + +<pre class="brush: css"><code>.box { + border: 1px solid black; +} </code></pre> + +<p>또는 박스의 한쪽 가장자리를 대상으로 지정할 수 있습니다. 예를 들면:</p> + +<pre class="brush: css"><code>.box { + border-top: 1px solid black; +} </code></pre> + +<p>이러한 속기의 개별 속성은 다음과 같습니다:</p> + +<pre class="brush: css"><code>.box { + border-width: 1px; + border-style: solid; + border-color: black; +} </code></pre> + +<p>그리고 longhands 는 다음과 같습니다:</p> + +<pre class="brush: css"><code>.box { + border-top-width: 1px; + border-top-style: solid; + border-top-color: black; +} </code></pre> + +<div class="blockIndicator note"> +<p><strong>참고</strong>: 위쪽, 오른쪽, 아래쪽 및 왼쪽 테두리 속성에는 문서의 쓰기 모드 (예: 왼쪽에서 오른쪽으로 또는 오른쪽에서 왼쪽으로 텍스트 또는 위에서 아래로) 와 관련된 논리적 속성이 매핑되어 있습니다. 다음 수업에서는 <a href="/en-US/docs/Learn/CSS/Building_blocks/Handling_different_text_directions">다양한 텍스트 방향 처리</a> 에 대해 다룰것입니다.</p> +</div> + +<p><strong>테두리에 사용할 수 있는 다양한 스타일이 있습니다. 아래 예에서 우리는 박스의 네 면에 다른 테두리 스타일을 사용했습니다. 테두리 스타일, 너비 및 색상으로 실습하여 테두리의 작동 방식을 확인 하십시오.</strong></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/backgrounds-borders/borders.html", '100%', 800)}}</p> + +<h3 id="둥근_테두리">둥근 테두리</h3> + +<p>박스의 둥근 테두리는 {{cssxref("border-radius")}} 속성 과 박스의 각 모서리와 관련되 관련 longhands 를 사용하여 수행됩니다. 두 개의 길이 또는 백분율을 값으로 사용할 수 있습니다. 첫 번째 값은 가로 반경을 정의하고 두 번째 값은 세로 반경을 정의합니다. 많은 경우에 하나의 값만 전달하면 둘 다에 사용됩니다.</p> + +<p>예를 들어, 박스의 네 모서리를 모두 10px radius 로 만들려면:</p> + +<pre class="brush: css"><code>.box { + border-radius: 10px; +} </code></pre> + +<p>또는 오른쪽 상단 모서리의 가로 반경이 1em 이고, 세로 반경이 10% 가 되도록 하려면:</p> + +<pre class="brush: css"><code>.box { + border-top-right-radius: 1em 10%; +} </code></pre> + +<p>아래 예에서 네 모서리를 모두 설정한 다음, 오른쪽 위 모서리의 값을 변경하여 다르게 만들었습니다. 값을 사용하여 모서리를 변경할 수 있습니다. 사용 가능한 구문 옵션을 보려면 {{cssxref("border-radius")}} 의 속성 페이지를 살펴보십시오.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/backgrounds-borders/corners.html", '100%', 800)}}</p> + +<h2 id="배경과_테두리로_실습하기">배경과 테두리로 실습하기</h2> + +<p>새로운 지식을 테스트하려면 아래 예제를 시작점으로 사용하여 배경과 테두리를 사용하여 다음을 작성하십시오:</p> + +<ol> + <li>박스에 둥근 모서리가 10px 인, 5px 검은색 단색 테두리를 지정하십시오.</li> + <li>배경 이미지를 추가하고 (URL <code>balloons.jpg</code> 사용) 박스를 덮도록 크기를 조정하십시오.</li> + <li><code><h2></code> 에 반투명 검정색 배경색을 지정하고 텍스트를 흰색으로 만듭니다.</li> +</ol> + +<p>{{EmbedGHLiveSample("css-examples/learn/backgrounds-borders/task.html", '100%', 800)}}</p> + +<div class="blockIndicator note"> +<p><strong>참고</strong>: <a href="https://github.com/mdn/css-examples/blob/master/learn/solutions.md">여기에서 해결책을 살펴 보기</a> 할 수 있지만 — 먼저 스스로 알아보십시오!</p> +</div> + +<h2 id="요약">요약</h2> + +<p>여기서는 많은 내용을 다루었으며, 박스에 배경이나 데두리를 추가하는 것이 상당히 많다는 것을 알 수 있습니다. 논의한 기능에 대해 더 자세히 알고 싶다면, 다른 속성 페이지를 살펴보십시오. MDN 의 각 페이지에는 지식을 가지고 실습하고 향상시키기 위한 더 많은 사용 예제가 있습니다.</p> + +<p>다음 수업에서는 문서의 쓰기 모드가 CSS 와 어떻게 상호 작용하는지 알아봅니다. 텍스트가 왼쪽에서 오른쪽으로 표시되지 않으면 어떻게 됩니까?</p> + +<p>{{PreviousMenuNext("Learn/CSS/Building_blocks/The_box_model", "Learn/CSS/Building_blocks/Handling_different_text_directions", "Learn/CSS/Building_blocks")}}</p> + +<h2 id="이번_강의에서는">이번 강의에서는</h2> + +<ol> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance">계단식 및 상속</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors">CSS 선택자</a> + <ul> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Type_Class_and_ID_Selectors">Type, class 및 ID 선택자</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Attribute_selectors">속성 선택자</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Pseudo-classes_and_pseudo-elements">Pseudo-classes 및 pseudo-elements</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Combinators">결합자</a></li> + </ul> + </li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/The_box_model">박스 모델</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Backgrounds_and_borders">배경 및 테두리</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Handling_different_text_directions">다른 텍스트 방향 처리</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Overflowing_content">콘텐츠 overflow</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Values_and_units">값 과 단위</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Sizing_items_in_CSS">CSS 에서 항목 크기 조정</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Images_media_form_elements">이미지, 미디어 및 양식 요소</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Styling_tables">표 스타일링</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Debugging_CSS">CSS 디버깅</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Organizing">CSS 정리</a></li> +</ol> diff --git a/files/ko/learn/css/building_blocks/cascade_and_inheritance/index.html b/files/ko/learn/css/building_blocks/cascade_and_inheritance/index.html new file mode 100644 index 0000000000..5e15af3722 --- /dev/null +++ b/files/ko/learn/css/building_blocks/cascade_and_inheritance/index.html @@ -0,0 +1,337 @@ +--- +title: 계단식 및 상속 +slug: Learn/CSS/Building_blocks/Cascade_and_inheritance +translation_of: Learn/CSS/Building_blocks/Cascade_and_inheritance +--- +<div>{{LearnSidebar}}{{NextMenu("Learn/CSS/Building_blocks/Selectors", "Learn/CSS/Building_blocks")}}</div> + +<p>이 수업의 목적은 CSS 가 HTML 에 적용되는 방법과 충돌을 해결하는 방법을 제어하는 CSS 의 가장 기본적인 개념인 — 계단식, 우선 순위 및 상속 — 에 대한 이해를 발전시키는 것입니다.</p> + +<p>이 수업을 통해 작업하면 코스의 다른 부분 보다 관련성이 떨어지고 좀 더 학문적으로 보일 수 있지만, 이러한 사항을 이해하면 나중에 많은 고통을 덜 수 있습니다! 이 섹션을 주의 깊게 살펴보고 계속 진행하기 전에 개념을 이해하는지 확인하십시오.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">전제조건:</th> + <td>기본 컴퓨터 활용 능력, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Installing_basic_software">기본 소프트웨어 설치</a>, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Dealing_with_files">파일 작업</a> 에 대한 기본 지식, HTML 기본 사항 (<a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">HTML 소개</a> 학습) 및 , CSS 작동 방식 이해 (<a href="/en-US/docs/Learn/CSS/First_steps">CSS 첫 번째 단계</a> 학습)</td> + </tr> + <tr> + <th scope="row">목적:</th> + <td>계단식 및 특수성 과 CSS 에서 상속이 작동하는 방식 배우기.</td> + </tr> + </tbody> +</table> + +<h2 id="규칙_충돌">규칙 충돌</h2> + +<p>CSS 는 <strong>Cascading Style Sheets</strong> 의 약자이며, CSS 라는 단어를 이해하는 데 있어 첫 번째 단어 <em>cascading</em> 은 매우 중요합니다.</p> + +<p>어느 시점에서, 당신은 프로젝트를 진행할 것이며 요소에 적용해야 할 CSS 가 작동하지 않는다는 것을 알게 될 것입니다. 일반적으로 문제는 동일한 요소에 적용할 수 있는 두 가지 규칙을 작성 했다는 것입니다. <strong>계단식 (cascade)</strong> 과 밀접하게 관련된 <strong>우선 순위 (specificity)</strong> 개념은 그러한 충돌이 있을 때 적용되는 규칙을 제어하는 메커니즘입니다. 어떤 규칙에 따라 요소를 원하는 스타일로 만들지 못할 수도 있으므로 이러한 메커니즘의 작동 방식을 이해해야 합니다.</p> + +<p><strong>상속(inheritance)</strong> 개념도 중요합니다. 기본적으로 일부 CSS 속성은 현재 요소의 부모 요소에 설정된 값을 상속하지만, 일부는 그렇지 않습니다. 또한 예상치 못한 일부 동작이 발생할 수 있습니다.</p> + +<p>우리가 다루고 있는 주요 사항을 간단히 살펴보면서 시작해 봅시다. 차례대로 살펴보고 서로 상호 작용하고 CSS 와 어떻게 상호 작용 하는지 살펴 보겠습니다. 이것은 이해하기 어려운 까다로운 개념으로 보일 수 있습니다. 그러나 CSS 작성에 대한 연습이 많을수록 작동 방식이 더 명확해 집니다.</p> + +<h3 id="계단식_cascade">계단식 (cascade)</h3> + +<p>스타일 시트 <strong>cascade</strong> — 매우 간단한 수준에서 이는 CSS 규칙의 순서가 중요하다는 것을 의미 합니다. 동일한 우선 순위를 갖는 두 규칙이 적용될 때, CSS 에서 마지막에 나오는 규칙이 사용 될 것입니다.</p> + +<p>아래 예에서는, <code>h1</code> 에 적용할 수 있는 두 가지 규칙이 있습니다. <code>h1</code> 은 파란색으로 표시됩니다 — 이러한 규칙에는 동일한 선택자가 있고 동일한 고유성을 가지므로, 소스 순서의 마지막 규칙이 우선합니다.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/cascade/cascade-simple.html", '100%', 400)}} </p> + +<h3 id="우선_순위_Specificity">우선 순위 (Specificity)</h3> + +<p>우선 순위는 여러 규칙에 다른 선택자가 있지만, 여전히 동일한 요소에 적용될 수 있는 경우, 브라우저가 어떤 규칙을 적용할 지 결정하는 방법입니다. 기본적으로 선택자의 선택이 얼마나 구체적인지 측정합니다:</p> + +<ul> + <li>요소 선택자는 덜 구체적입니다 — 페이지에 나타나는 해당 유형의 모든 요소를 선택하므로 — 점수가 낮아집니다.</li> + <li>class 선택자는 보다 구체적입니다 — 특정 <code>class</code> 속성 값이 있는 페이지의 요소만 선택하므로 — 점수가 높아집니다.</li> +</ul> + +<p>시간 예제! 아래에는 <code>h1</code> 에 적용할 수 있는 두 가지 규칙이 다시 있습니다. 아래 <code>h1</code> 은 빨간색으로 표시 됩니다 — class 선택자는 규칙에 더 높은 우선 순위를 부여하므로 요소 선택자가 있는 규칙은 소스 순서에서 더 아래에 표시 되더라도 적용됩니다.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/cascade/specificity-simple.html", '100%', 500)}} </p> + +<p>우선 순위 점수 및 기타 사항에 대해서는 나중에 설명하겠습니다.</p> + +<h3 id="상속_Inheritance">상속 (Inheritance)</h3> + +<p>상속은 이 맥락에서 이해되어야 합니다 — 부모 요소에서 설정된 일부 CSS 속성 값은 자식 요소에 의해 상속되며, 일부는 그렇지 않습니다.</p> + +<p>예를 들어, 요소에 <code>color</code> 및 <code>font-family</code> 를 설정하면, 다른 색상 및 글꼴 값을 직접 적용하지 않는 한, 해당 요소 내부의 모든 요소에도 해당 색상 및 글꼴로 스타일이 지정됩니다.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/cascade/inheritance-simple.html", '100%', 550)}} </p> + +<p>일부 속성은 상속되지 않습니다 — 예를 들어 요소에 {{cssxref("width")}} 를 50% 로 설정하면, 모든 하위 항목의 너비가 부모 너비의 50% 가 되지 않습니다. 이 경우, CSS 는 사용하기가 매우 어려울 것입니다!</p> + +<div class="blockIndicator note"> +<p><strong>참고</strong>: MDN CSS 속성 참조 페이지에서 일반적으로 specifications 섹션의 맨 아래에 기술 정보 박스가 있습니다. 여기에는 해당 속성의 상속 여부를 포함하여 해당 속성에 대한 여러 데이터 요소가 나열되어 있습니다. 예를 들어, <a href="/en-US/docs/Web/CSS/color#Specifications">color 속성 Specifications 섹션</a> 을 참조 하십시오.</p> +</div> + +<h2 id="개념이_함께_작동하는_방식_이해하기">개념이 함께 작동하는 방식 이해하기</h2> + +<p>이 세 가지 개념은 어떤 CSS 가 어떤 요소에 적용되는지를 함께 제어합니다. 아래 섹션에서 우리는 그들이 어떻게 함께 작동하는지 볼 것입니다. 때로는 약간 복잡해 보일 수 있지만, CSS 에 익숙해지면 기억하기 시작하고 잊어 버린 경우, 항상 세부 정보를 찾을 수 있습니다! 숙련된 개발자 조차도 모든 세부 사항을 기억하지 못합니다.</p> + +<h2 id="상속_이해하기">상속 이해하기</h2> + +<p>상속부터 시작하겠습니다. 아래 예에서는 {{HTMLElement("ul")}} 이 있으며, 그 안에 순서가 없는 두 가지 수준의 목록이 있습니다. 외부 <code><ul></code> 에 테두리, 패딩 및 글꼴 색상을 지정했습니다.</p> + +<p>색상은 직접 자식 항목 뿐만 아니라 간접 자식 항목 (직접 자식 <code><li></code>) 및 첫 번째 중첩 목록에 있는 자식 항목에도 적용됩니다. 그런 다음 두 번째 중첩 목록에 <code>special</code> class 를 추가하고 다른 색상을 적용했습니다. 그런 다음 자식을 통해 상속됩니다.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/cascade/inheritance.html", '100%', 700)}} </p> + +<p>너비 (위에서 언급 한 것처럼), 마진, 패딩 및 테두리와 같은 것은 상속되지 않습니다. 만약 우리 목록의 자식들이 테두리를 물려 받았다면, 모든 단일 목록과 목록 항목은 테두리를 얻게 될 것입니다 — 아마도 우리가 원하는 효과는 아닙니다!</p> + +<p>기본적으로 상속되는 속성과 그렇지 않은 속성은 대체로 상식적입니다.</p> + +<h3 id="상속_제어하기">상속 제어하기</h3> + +<p>CSS 는 상속을 제어하기 위한 4 가지 특수 범용 속성 값을 제공합니다. 모든 CSS 속성은 이러한 값을 허용합니다.</p> + +<dl> + <dt>{{cssxref("inherit")}}</dt> + <dd>선택한 요소에 적용된 속성 값을 부모 요소의 속성 값과 동일하게 설정합니다. 사실상, 이것은 "상속에 영향을 미칩니다".</dd> + <dt>{{cssxref("initial")}}</dt> + <dd>선택한 요소에 적용된 속성 값을 브라우저의 기본 스타일 시트에서 해당 요소의 해당 속성에 설정된 값과 동일하게 설정합니다. 브라우저의 기본 스타일 시트에서 값을 설정하지 않고 속성이 자연스럽게 상속되면 속성 값이 대신 <code>inherit</code> 되도록 설정됩니다.</dd> + <dt>{{cssxref("unset")}}</dt> + <dd>속성을 natural 값으로 재설정 합니다. 즉, 속성이 자연적으로 상속되면 <code>inherit</code> 된 것처럼 작동하고 그렇지 않으면 <code>initial</code> 처럼 작동합니다.</dd> +</dl> + +<div class="blockIndicator note"> +<p><strong>참고</strong>: 브라우저 지원이 제한된 새로운 값인 {{cssxref("revert")}} 도 있습니다.</p> +</div> + +<div class="blockIndicator note"> +<p><strong>참고</strong>: 각각에 대한 자세한 내용과 작동 방식에 대한 자세한 내용은 {{SectionOnPage("/en-US/docs/Web/CSS/Cascade", "Origin of CSS declarations")}} 를 참조하십시오.</p> +</div> + +<p>우리는 링크 목록을 보고 보편적 가치가 어떻게 작용하는지 탐구할 수 있습니다. 아래의 라이브 예제를 사용하면 CSS 를 사용하여 변경 작업을 수행할 수 있습니다. 코드를 가지고 노는 것이 HTML 과 CSS 를 이해하는 가장 좋은 방법입니다.</p> + +<p>예를 들면:</p> + +<ol> + <li>두 번째 목록 항목에는 <code>my-class-1</code> class 가 적용되었습니다. 내부에 중첩된 <code><a></code> 요소의 색상을 상속하도록 설정합니다. 규칙을 제거하면 링크 색상이 어떻게 변경됩니까?</li> + <li>왜 세 번째 와 네 번째 링크가 그 색깔인지 이해합니까? 그렇치 않은 경우 위의 값에 대한 설명을 확인하십시오.</li> + <li><code><a></code> 요소에 대해 — 예를 들어 <code>a { color: red; }</code> 와 같은 새 색상을 정의하는 경우 어떤 링크가 색상이 변경됩니까?</li> +</ol> + +<p>{{EmbedGHLiveSample("css-examples/learn/cascade/keywords.html", '100%', 700)}} </p> + +<h3 id="모든_속성_값_재설정">모든 속성 값 재설정</h3> + +<p>CSS 속기 속성을 <code>all</code> 로 사용하면 이러한 상속 값 중 하나를 (거의) 모든 속성에 한 번에 적용할 수 있습니다. 이 값은 상속 값 (<code>inherit</code>, <code>initial</code>, <code>unset</code> 또는 <code>revert</code>) 중 하나일 수 있습니다. 스타일에 대한 변경 사항을 취소하여 새로운 변경을 시작하기 전에 알려진 시작 지점으로 돌아갈 수 있는 편리한 방법입니다.</p> + +<p>아래 예제에는 두 개의 인용문이 있습니다. 첫 번째는 인용문 자체에 스타일을 적용하고 두 번째는 <code>all</code> 값을 <code>unset</code> 하도록 인용문에 적용된 class 를 갖습니다.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/cascade/all.html", '100%', 700)}} </p> + +<p><code>all</code> 의 값을 사용 가능한 다른 값 중 일부로 설정하고 차이가 무엇인지 관찰하십시오.</p> + +<h2 id="계단식_cascade_이해하기">계단식 (cascade) 이해하기</h2> + +<p>이제 HTML 구조에 깊게 중첩된 단락이 본문에 적용된 CSS 와 동일한 색상인 이유를 이해하고, 소개 수업에서 문서의 어느 시점에서는 CSS 를 변경하는 방법에 대해 이해합니다 — 요소에 CSS 를 할당하거나 class 를 만들지 여부. 이제 여러 요소가 요소를 스타일링 할 수 있는 경우, CSS 에서 적용할 CSS 규칙을 어떻게 정의하는지 계단식 (cascade) 에 대해 올바르게 살펴보겠습니다.</p> + +<p>여기에는 중요도의 내림차순으로 나열된 세 가지 요소가 있습니다. 이전의 것들은 다음 것보다 우선합니다:</p> + +<ol> + <li><strong>Importance</strong></li> + <li><strong>우선 순위</strong></li> + <li><strong>소스 순서</strong></li> +</ol> + +<p>브라우저가 CSS 를 정확히 적용하는 방법을 어떻게 파악하는지 아래부터 위로 살펴보겠습니다.</p> + +<h3 id="소스_순서">소스 순서</h3> + +<p>우리는 이미 소스 순서가 계단식 (cascade) 에 어떻게 중요한지를 보았습니다. 정확히 동일한 가중치를 갖는 규칙이 두 개 이상인 경우, CSS 에서 마지막에 오는 규칙이 우선합니다. 이것을 요소 자체가 마지막 요소가 승리하고 요소를 스타일링 할 때까지 초기 요소를 덮어 쓰는 규칙에 가깝다고 생각할 수 있습니다.</p> + +<h3 id="우선_순위_Specificity_2">우선 순위 (Specificity)</h3> + +<p>소스 순서가 중요하다는 사실을 이해하면, 어느 시점에서 규칙이 스타일 시트에서 나중에 나오지만 이전의 충돌하는 규칙이 적용되는 상황이 발생합니다. 이는 이전 규칙이 더 <strong>높은 우선 순위</strong>를 갖기 때문입니다 — 보다 구체적이기 때문에, 브라우저에서 요소를 스타일해야 하는 규칙으로 선택하고 있습니다.</p> + +<p>이 수업의 앞부분에서 살펴본 것처럼, class 선택자는 요소 선택자보다 가중치가 높으므로, class 에 정의된 속성이 요소에 직접 적용된 속성보다 우선합니다.</p> + +<p>여기서 주목할 점은 선택자 및 선택한 항목에 적용되는 규칙에 대해 생각하고 있지만, 덮어 쓰는 전체 규칙이 아니라 동일한 속성일 뿐입니다.</p> + +<p>이 동작은 CSS 에서 반복을 피하는 데 도움이 됩니다. 일반적인 방법은 기본 요소의 일반 스타일을 정의한 다음, 다른 요소에 대한 class 를 작성하는 것입니다. 예를 들어, 아래 스타일 시트에서 h2 제목에 대한 일반 스타일을 정의한 다음, 일부 속성과 값만 변경하는 class 를 만들었습니다. 처음에 정의된 값은 모든 표제에 적용되며, 보다 구체적인 값은 class 가 있는 표제에 적용됩니다.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/cascade/mixing-rules.html", '100%', 700)}} </p> + +<p>이제 브라우저가 우선 순위 (specificity) 를 계산하는 방법을 살펴보겠습니다. 우리는 이미 요소 선택자가 우선 순위가 낮으며 class 가 덮어 쓸 수 있음을 알고 있습니다. 기본적으로 포인트 단위의 가치가 다른 유형의 선택자에 부여되며, 이를 합산하면 특정 선택자의 가중치가 부여되며, 이는 다른 잠재적 일치 항목에 대해 평가할 수 있습니다.</p> + +<p>선택자의 우선 순위는 4개의 다른 값 (또는 구성 요소) 을 사용하여 측정되며, 이는 4개의 열에서 Thousands, Hundreds, Tens 및 Ones<strong> </strong>개의 단일 자릿수로 간주될 수 있습니다.</p> + +<ol> + <li><strong>Thousands</strong>: 선언이 인라인 스타일인 {{htmlattrxref("style")}} 속성 안에 있으면, 열에서 1점을 얻습니다. 이러한 선언에는 선택자가 없으므로 그 우선 순위는 항상 1000 입니다.</li> + <li><strong>Hundreds</strong>: 전체 선택자에 포함된 각 ID 선택자에 대해 이 열에서 1점을 얻습니다.</li> + <li><strong>Tens</strong>: 이 선택란에서 전체 선택자 내에 포함된 각 class 선택자, 속성 선택자 또는 pseudo-class 에 대해 이 열에서 1점을 얻습니다.</li> + <li><strong>Ones</strong>: 이 항목에서 각 요소 선택자 또는 전체 선택자 내에 포함된 pseudo-element 에 대해 1점을 얻습니다.</li> +</ol> + +<div class="note"> +<p><strong>참고</strong>: 범용 선택자 (<code>*</code>), 결합자 (<code>+</code>, <code>></code>, <code>~</code>, ' ') 및 부정 pseudo-class (<code>:not</code>) 는 우선 순위에 영향을 미치지 않습니다.</p> +</div> + +<p>다음 표는 기분을 전환하기 위해 몇 가지 분리된 예를 보여줍니다. 이것들을 살펴보고 왜 그들이 우리에게 그들에게 주어진 우선 순위를 가지고 있는지 이해하도록 하십시오. 선택자는 아직 자세히 다루지 않았지만, MDN <a href="/en-US/docs/Web/CSS/CSS_Selectors">선택자 참조</a> 에서 각 선택자의 세부 정보를 찾을 수 있습니다.</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">선택자</th> + <th scope="col">Thousands</th> + <th scope="col">Hundreds</th> + <th scope="col">Tens</th> + <th scope="col">Ones</th> + <th scope="col">Total specificity</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>h1</code></td> + <td>0</td> + <td>0</td> + <td>0</td> + <td>1</td> + <td>0001</td> + </tr> + <tr> + <td><code>h1 + p::first-letter</code></td> + <td>0</td> + <td>0</td> + <td>0</td> + <td>3</td> + <td>0003</td> + </tr> + <tr> + <td><code>li > a[href*="en-US"] > .inline-warning</code></td> + <td>0</td> + <td>0</td> + <td>2</td> + <td>2</td> + <td>0022</td> + </tr> + <tr> + <td><code>#identifier</code></td> + <td>0</td> + <td>1</td> + <td>0</td> + <td>0</td> + <td>0100</td> + </tr> + <tr> + <td>요소의 {{htmlattrxref("style")}} 속성 안에 규칙이 있는 선택자가 없습니다</td> + <td>1</td> + <td>0</td> + <td>0</td> + <td>0</td> + <td>1000</td> + </tr> + </tbody> +</table> + +<p>계속 진행하기 전에, 실제 사례를 살펴보겠습니다.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/cascade/specificity-boxes.html", '100%', 700)}} </p> + +<p>우선, 우리는 이 예제의 처음 7개 규칙에만 관심이 있으며, 앞으로 알 수 있듯이 각 규칙 앞에 주석에 우선 순위 값을 포함 시켰습니다.</p> + +<ul> + <li>처음 두 선택자는 링크의 배경색 스타일링을 놓고 경쟁합니다 — 두 번째 선택자는 추가 ID 선택자가 있기 때문에 이기고 배경색을 파란색으로 만듭니다: 우선 순위는 201 vs 101 입니다.</li> + <li>세 번째와 네 번째 선택자는 링크의 텍스트 색상 스타일링을 놓고 경쟁하고 있습니다 — 두 번째 선택자는 이기고 텍스트는 흰색으로 만듭니다. 왜냐하면 한 개의 요소 선택자가 더 적지만, 누락된 선택자는 10배의 가치가 있는 class 선택자로 교체되기 때문입니다. 그래서 승자의 우선 순위는 113 vs 104 입니다.</li> + <li>선택자 5–7 은 마우스를 가져 가면 링크의 테두리 스타일을 놓고 경쟁합니다. 선택자 6은 23 vs 24 의 우선 순위로 5점이 확실히 손실됩니다 — 요소 선택자가 하나 더 적습니다. 선택자 7은 5 와 6을 모두 능가합니다 — 5와 동일한 수의 자식 선택자가 있지만, 한 요소는 class 선택자로 교체되었습니다. 따라서 승자의 우선 순위는 33 vs 23 및 24 입니다.</li> +</ul> + +<ol> +</ol> + +<div class="note"> +<p><strong>참고</strong>: 이것은 이해를 돕기위한 대략적인 예일뿐입니다. 실제로 각 선택자 유형에는 고유한 순위가 있으며, 낮은 우선 순위의 선택자로 덮어쓸 수 없습니다. 예를 들어, <em>백 만</em> 개의 <strong>class</strong> 선택자가 결합되어도 <em>하나 </em>의 <strong>id</strong> 선택자의 규칙을 겹쳐쓸 수 없습니다.</p> + +<p>우선 순위를 평가하는 보다 정확한 방법은 우선 순위를 개별적으로 최고에서 시작하여 필요할 때 최저로 평가하는 것입니다. 특정 순위 내에서 선별 점수 사이에 동점이 있을 때만 다음 수준을 평가해야 합니다. 그렇지 않으면, 낮은 우선 순위 선택자는 높은 우선 순위를 덮어쓸 수 없으므로 무시할 수 있습니다.</p> +</div> + +<h3 id="!important">!important</h3> + +<p>위의 모든 계산을 무효화하는 데 사용할 수 있는 특별한 CSS 가 있지만, 중요하게 사용해야 합니다 — <code>!important</code>. 이것은 특정 속성과 가치를 가장 구체적으로 만들어 계단식 (cascade) 의 일반적인 규칙을 무시하는 데 사용됩니다.</p> + +<p>두 개의 단락이 있고, 하나에 ID 가 있는 이 예를 살펴보십시오.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/cascade/important.html", '100%', 700)}} </p> + +<p>이 과정을 통해 어떤 일이 일어나고 있는지 살펴보겠습니다 — 이해하기 어려운 경우 어떤 일이 발생하는지 확인하려면 일부 속성을 제거해 보십시오:</p> + +<ol> + <li>세 번째 규칙의 {{cssxref("color")}} 및 {{cssxref("padding")}} 값이 적용되었지만, {{cssxref("background-color")}} 가 적용되었음을 알 수 있습니다. 왜죠? 소스 순서 후반의 규칙은 일반적으로 이전 규칙보다 우선하기 때문에 세 가지 모두가 반드시 적용되어야 합니다.</li> + <li>그러나, class 선택자는 요소 선택자보다 높은 우선 순위에 있기 때문에 위의 규칙이 우선합니다.</li> + <li>두 요소 모두 {{htmlattrxref("class")}} 가 <strong><code>더 우수</code></strong> 하지만, 두 번째 요소는 {{htmlattrxref("id")}} 도 <strong><code>이기고</code></strong> 있습니다. ID 는 classe 보다 우선 순위가 <em>더 높기</em> 때문에 페이지에서 각 고유 ID 를 가진 요소는 하나만 가질 수 있지만, class 는 같은 요소가 많습니다 — ID 선택자는 대상에 따라 <strong><em>매우 다릅니다</em>.</strong> 빨간색 배경색과 1 px 검은색 테두리를 두 번째 요소에 적용해야 합니다. 첫 번째 요소는 회색 배경색을 가져오고 class 에서 지정한대로 테두리가 없습니다.</li> + <li>두 번째 요소는 빨간색 배경색을 얻지만, 테두리는 없습니다. 왜일까요? 두 번째 규칙의 <code>!important</code> 선언으로 인해 — <code>border: none</code> 뒤에 이것을 포함하면 ID 가 더 높은 우선 순위에도 불구하고 이 선언이 이전 규칙의 테두리 값 보다 우선함을 의미합니다.</li> +</ol> + +<div class="note"> +<p><strong>참고</strong>: 이 <code>!important</code> 선언을 재정의하는 유일한 방법은 소스 순서에서 나중에 같은 우선 순위를 가진 선언에 또는 다른 고유한 선언에 다른 <code>!important</code> 선언을 포함시키는 것입니다.</p> +</div> + +<p><code>!important</code> 가 존재한다는 것을 아는 것이 도움이 되므로 다른 사람들의 코드에서 그것을 발견할 때 그 의미를 알 수 있습니다. <strong>그러나, 반드시 필요한 경우가 아니면 절대 사용하지 않는 것이 좋습니다. </strong><code>!important</code> 는 계단식이 정상적으로 작동하는 방식을 변경하므로, CSS 스타일 문제를 해결하기가 어렵습니다. 특히 큰 스타일 시트에서.</p> + +<p>핵심 CSS modules 을 편집할 수 없는 CMS 에서 작업할 때, 다른 방법으로는 재정의 할 수 없는 스타일을 재정의 하려는 경우에 사용할 수도 있습니다. 그러나 실제로 피할 수 있다면 사용하지 마십시오.</p> + +<h2 id="CSS_위치의_영향">CSS 위치의 영향</h2> + +<p>마지막으로, CSS 선언의 중요성은 지정된 스타일 시트에 따라 다릅니다 — 사용자가 스타일 시트를 설정하여 개발자의 스타일을 재정의할 수 있습니다. 예를 들어, 사용자가 시각 장애인일 수 있으며, 쉽게 읽을 수 있도록 방문하는 모든 웹 페이지의 글꼴 크기를 일반 크기의 두 배로 설정하려고 합니다.</p> + +<h2 id="요약하자면">요약하자면</h2> + +<p>충돌 선언은 다음 순서로 적용되며, 이후 선언은 이전 선언보다 우선합니다:</p> + +<ol> + <li>사용자 에이전트 스타일 시트의 선언 (예: 다른 스타일이 설정되지 않은 경우 사용되는 브라우저의 기본 스타일).</li> + <li>사용자 스타일 시트의 일반 선언 (사용자가 설정한 사용자 정의 스타일).</li> + <li>작성자 스타일 시트의 일반적인 선언 (웹 개발자가 설정한 스타일).</li> + <li>작성자 스타일 목록에서 중요한 선언</li> + <li>사용자 스타일 시트의 중요한 선언</li> +</ol> + +<p>웹 개발자의 스타일 시트는 사용자 스타일 시트를 재정의 하는것이 합리적이므로 디자인을 의도한대로 유지할 수 있지만, 사용자는 위에서 언급한 것처럼 웹 개발자 스타일을 재정의 해야 할 충분한 이유가 있습니다 — 이는 규칙에서 <code>important</code> 를 사용하여 달성할 수 있습니다.</p> + +<h2 id="적극적인_학습_계단식_게임입니다">적극적인 학습: 계단식 게임입니다</h2> + +<p>이 적극적인 학습에서는, 기본적으로 링크에 적용한 색상 및 배경색을 재정의하는 새로운 규칙 하나를 작성하여 실험해 보고자 합니다. {{anch("상속 제어")}} 섹션에서 살펴본 특수값 중 하나를 사용하여 실제 색상값을 사용하지 않고 배경색상을 다시 흰색으로 재설정하는 새 규칙에 선언을 작성할 수 있습니까?</p> + +<p>실수한 경우 언제든지 <em>재설정</em> 버튼을 사용하여 재설정 할 수 있습니다. 정말로 막힌다면, <a href="https://github.com/mdn/css-examples/blob/master/learn/solutions.md#the-cascade">여기에서 해결책을 살펴 보십시오</a>.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/cascade/task.html", '100%', 700)}}</p> + +<h2 id="다음은_뭐죠">다음은 뭐죠</h2> + +<p>이 기사의 대부분을 이해했다면, 잘 끝났습니다 — CSS 의 기본 메커니즘에 익숙해지기 시작했습니다. 다음으로 선택자를 자세히 살펴보겠습니다.</p> + +<p>계단식, 우선 순위 및 상속을 완전히 이해하지 못했다면, 걱정하지 마십시오! 이것은 지금까지 우리가 다루었던 가장 복잡한 내용이며, 전문 웹 개발자 조차도 까다로워하는 부분입니다. 강의를 계속 진행하면서, 이 기사를 몇 차례 다시 읽고 계속 생각하는 것이 좋습니다.</p> + +<p>스타일이 예상대로 적용되지 않는 이상한 문제가 발생하면 여기를 다시 참조 하십시오. 우선 순위 문제일 수 있습니다.</p> + +<p>{{NextMenu("Learn/CSS/Building_blocks/Selectors", "Learn/CSS/Building_blocks")}}</p> + +<h2 id="이번_강의에서는">이번 강의에서는</h2> + +<ol> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance">계단식 및 상속</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors">CSS 선택자</a> + <ul> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Type_Class_and_ID_Selectors">Type, class 및 ID 선택자</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Attribute_selectors">속성 선택자</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Pseudo-classes_and_pseudo-elements">Pseudo-classes 및 pseudo-elements</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Combinators">결합자</a></li> + </ul> + </li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/The_box_model">박스 모델</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Backgrounds_and_borders">배경 및 테두리</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Handling_different_text_directions">다른 텍스트 방향 처리</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Overflowing_content">콘텐츠 overflowing</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Values_and_units">값 과 단위</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Sizing_items_in_CSS">CSS 에서 항목 크기 조정</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Images_media_form_elements">이미지, 미디어 및 양식 요소</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Styling_tables">표 스타일링</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Debugging_CSS">CSS 디버깅</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Organizing">CSS 정리</a></li> +</ol> diff --git a/files/ko/learn/css/building_blocks/debugging_css/index.html b/files/ko/learn/css/building_blocks/debugging_css/index.html new file mode 100644 index 0000000000..bf8badc26b --- /dev/null +++ b/files/ko/learn/css/building_blocks/debugging_css/index.html @@ -0,0 +1,200 @@ +--- +title: CSS 디버깅 +slug: Learn/CSS/Building_blocks/Debugging_CSS +translation_of: Learn/CSS/Building_blocks/Debugging_CSS +--- +<div>{{LearnSidebar}}{{PreviousMenuNext("Learn/CSS/Building_blocks/Styling_tables", "Learn/CSS/Building_blocks/Organizing", "Learn/CSS/Building_blocks")}}</div> + +<p>때로는 CSS 를 작성할 때 CSS 가 예상한 대로 동작하지 않는 문제가 발생합니다. 아마도 특정 선택자가 요소와 일치해야 하지만, 아무일도 일어나지 않거나 박스의 크기가 예상과 다릅니다. 이 기사에서는 CSS 문제를 디버깅하는 방법에 대한 지침을 제공하고 모든 최신 브라우저에 포함된 DevTools 가 진행 상황을 찾는 데 어떻게 도움이 되는지 보여줍니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">전제조건:</th> + <td> + <p>기본 컴퓨터 활용 능력, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Installing_basic_software">기본 소프트웨어 설치</a>, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Dealing_with_files">파일 작업</a> 에 대한 기본 지식, HTML 기본 사항 (<a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">HTML 소개</a> 학습) 및 , CSS 작동 방식 이해 (<a href="/en-US/docs/Learn/CSS/First_steps">CSS 첫 번째 단계</a> 학습)</p> + </td> + </tr> + <tr> + <th scope="row">목적:</th> + <td>브라우저 DevTools 의 기본 사항과 CSS 의 간단한 검사 및 편집방법 배우기.</td> + </tr> + </tbody> +</table> + +<h2 id="브라우저_개발자_도구_DevTools_사용_방법">브라우저 개발자 도구 (DevTools) 사용 방법</h2> + +<p> <a href="https://wiki.developer.mozilla.org/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">브라우저 개발자 도구란</a> 기사는 다양한 브라우저 및 플랫폼에서 도구를 사용하는 방법을 설명하는 최신 안내서입니다. 대부분 특정 브라우저에서 개발하도록 선택할 수 있으므로, 해당 브라우저에 포함된 도구에 가장 익숙해지지만, 다른 브라우저에서 해당 도구에 액세스하는 방법을 알아야합니다. 여러 브라우저간에 다른 렌더링이 표시되는 경우 도움이됩니다.</p> + +<p>또한 DevTools 를 작성할 때 브라우저가 다른 영역에 집중하도록 선택했음을 알 수 있습니다. 예를 들어, Firefox 에는 CSS 레이아웃으로 시각적으로 작업하기위한 훌륭한 도구가 있으며, <a href="/en-US/docs/Tools/Page_Inspector/How_to/Examine_grid_layouts">그리드 레이아웃</a>, <a href="/en-US/docs/Tools/Page_Inspector/How_to/Examine_Flexbox_layouts">Flexbox</a> 및 <a href="/en-US/docs/Tools/Page_Inspector/How_to/Edit_CSS_shapes">Shapes</a> 를 검사하고 편집할 수 있습니다. 그러나, 모든 브라우저마다 유사한 기본 도구가 있습니다. 예: 페이지의 요소에 적용된 속성 및 값을 검사하고 편집기에서 변경하는 데 사용됩니다.</p> + +<p>이 수업에서는 CSS 작업을 위한 Firefox DevTools 의 유용한 기능을 살펴봅니다. 이를 위해 <a href="https://mdn.github.io/css-examples/learn/inspecting/inspecting.html">예제 파일</a> 을 사용하겠습니다. 따라하고 싶다면, 새 탭에 로드하고 위에 링크된 기사에 설명된대로 DevTools 를 여십시오.</p> + +<h2 id="DOM_vs_소스_보기">DOM vs 소스 보기</h2> + +<p>새로운 사용자를 개발자 도구 (DevTools) 로 체험할 수 있는 것은 웹 페이지의 <a href="/en-US/docs/Tools/View_source">소스 보기</a> 를 보거나 서버에 넣은 HTML 파일을 볼 때 표시되는 것과 개발자 도구의 <a href="/en-US/docs/Tools/Page_Inspector/UI_Tour#HTML_pane">HTML 창</a>에서 볼 수 있는 것의 차이입니다. 소스 보기를 통해 볼 수 있는 것과 거의 비슷해 보이지만 몇 가지 차이점이 있습니다.</p> + +<p>렌더링 된 DOM 에서 브라우저가 잘못 작성된 HTML 를 수정했을 수 있습니다. <code><h2></code> 를 열고 <code></h3></code>, 로 닫는 등의 요소를 잘못 닫은 경우, 브라우저는 수행하려는 작업을 파악하고 DOM 의 HTML 은 <code><h2></code> 를 <code></h2></code> 로 올바르게 닫습니다. 또한 브라우저에서는 모든 HTML 를 표준화하고, DOM 은 JavaScript 로 변경한 내용도 표시합니다.</p> + +<p>소스 보기는 서버에 저장된 HTML 소스 코드입니다. 개발자 도구의 <a href="/en-US/docs/Tools/Page_Inspector/How_to/Examine_and_edit_HTML#HTML_tree">HTML tree</a> 는 특정 시점에 브라우저가 렌더링하는 내용을 정확하게 보여주므로, 실제로 진행중인 상황에 대한 통찰력을 제공합니다.</p> + +<h2 id="적용된_CSS_검사">적용된 CSS 검사</h2> + +<p>페이지에서 요소를 마우스 오른쪽/ctrl 키를 누른 채 클릭하고 <em><strong>검사 (Inspect)</strong> </em>를 선택하거나, 개발자 도구 디스플레이 왼쪽의 HTML tree 에서 요소를 선택하십시오. <code>box1</code> class 의 요소를 선택하십시오; 이것은 테두리 박스가 그려진 페이지의 첫 번째 요소입니다.</p> + +<p><img alt="The example page for this tutorial with DevTools open." src="https://mdn.mozillademos.org/files/16606/inspecting1.png" style="border-style: solid; border-width: 1px; height: 1527px; width: 2278px;"></p> + +<p>If you look at the <a href="/en-US/docs/Tools/Page_Inspector/UI_Tour#Rules_view">Rules view</a> to the right of your HTML, you should be able to see the CSS properties and values applied to that element. You will see the rules directly applied to class <code>box1</code> and also the CSS that is being inherited by the box from its ancestors, in this case to <code><body></code>. This is useful if you are seeing some CSS being applied that you didn't expect. Perhaps it is being inherited from a parent element and you need to add a rule to overwrite it in the context of this element.</p> + +<p>Also useful is the ability to expand out shorthand properties. In our example the <code>margin</code> shorthand is used.</p> + +<p><strong>Click on the little arrow to expand the view, showing the different longhand properties and their values.</strong></p> + +<p><strong>You can toggle values in the Rules view on and off, when that panel is active — if you hold your mouse over it checkboxes will appear. Uncheck a rule's checkbox, for example <code>border-radius</code>, and the CSS will stop applying.</strong></p> + +<p>You can use this to do an A/B comparison, deciding if something looks better with a rule applied or not, and also to help debug it — for example if a layout is going wrong and you are trying to work out which property is causing the problem.</p> + +<h2 id="Editing_values">Editing values</h2> + +<p>In addition to turning properties on and off, you can edit their values. Perhaps you want to see if another color looks better, or wish to tweak the size of something? DevTools can save you a lot of time editing a stylesheet and reloading the page.</p> + +<p><strong>With <code>box1</code> selected, click on the swatch (the small colored circle) that shows the color applied to the border. A color picker will open up and you can try out some different colors; these will update in real time on the page. In a similar fashion, you could change the width or style of the border.</strong></p> + +<p><img alt="DevTools Styles Panel with a color picker open." src="https://mdn.mozillademos.org/files/16607/inspecting2-color-picker.png" style="border-style: solid; border-width: 1px; height: 1173px; width: 2275px;"></p> + +<h2 id="Adding_a_new_property">Adding a new property</h2> + +<p>You can add properties using the DevTools. Perhaps you have realised that you don't want your box to inherit the <code><body></code> element's font size, and want to set its own specific size? You can try this out in DevTools before adding it to your CSS file.</p> + +<p><strong>You can click the closing curly brace in the rule to start entering a new declaration into it, at which point you can start typing the new property and DevTools will show you an autocomplete list of matching properties. After selecting <code>font-size</code>, enter the value you want to try. You can also click the + button to add an additional rule with the same selector, and add your new rules there.</strong></p> + +<p><img alt="The DevTools Panel, adding a new property to the rules, with the autocomplete for font- open" src="https://mdn.mozillademos.org/files/16608/inspecting3-font-size.png" style="border-style: solid; border-width: 1px; height: 956px; width: 2275px;"></p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: There are other useful features in the Rules view too, for example declarations with invalid values are crossed out. You can find out more at <a href="/en-US/docs/Tools/Page_Inspector/How_to/Examine_and_edit_CSS">Examine and edit CSS</a>.</p> +</div> + +<h2 id="Understanding_the_box_model">Understanding the box model</h2> + +<p>In previous lessons we have discussed <a href="/en-US/docs/Learn/CSS/Building_blocks/The_box_model">the Box Model</a>, and the fact that we have an alternate box model that changes how the size of elements are calculated based on the size you give them, plus the padding and borders. DevTools can really help you to understand how the size of an element is being calculated.</p> + +<p>The <a href="/en-US/docs/Tools/Page_Inspector/UI_Tour#Layout_view">Layout view</a> shows you a diagram of the box model on the selected element, along with a description of the properties and values that change how the element is laid out. This includes a description of properties that you may not have explicitly used on the element, but which do have initial values set.</p> + +<p>In this panel, one of the detailed properties is the <code>box-sizing</code> property, which controls what box model the element uses.</p> + +<p><strong>Compare the two boxes with classes <code>box1</code> and <code>box2</code>. They both have the same width applied (400px), however <code>box1</code> is visually wider. You can see in the layout panel that it is using <code>content-box</code>. This is the value that takes the size you give the element and then adds on the padding and border width.</strong></p> + +<p>The element with a class of <code>box2</code> is using <code>border-box</code>, so here the padding and border is subtracted from the size that you have given the element. This means that the space taken up on the page by the box is the exact size that you specified — in our case <code>width: 400px</code>.</p> + +<p><img alt="The Layout section of the DevTools" src="https://mdn.mozillademos.org/files/16609/inspecting4-box-model.png" style="border-style: solid; border-width: 1px; height: 1532px; width: 2275px;"></p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: Find out more in <a href="/en-US/docs/Tools/Page_Inspector/How_to/Examine_and_edit_the_box_model">Examining and Inspecting the Box Model</a>.</p> +</div> + +<h2 id="Solving_specificity_issues">Solving specificity issues</h2> + +<p>Sometimes during development, but in particular when you need to edit the CSS on an existing site, you will find yourself having a hard time getting some CSS to apply. No matter what you do, the element just doesn't seem to take the CSS. What is generally happening here is that a more specific selector is overriding your changes, and here DevTools will really help you out.</p> + +<p>In our example file there are two words that have been wrapped in an <code><em></code> element. One is displaying as orange and the other hotpink. In the CSS we have applied:</p> + +<pre class="brush: css">em { + color: hotpink; + font-weight: bold; +}</pre> + +<p>Above that in the stylesheet however is a rule with a <code>.special</code> selector:</p> + +<pre class="brush: css">.special { + color: orange; +}</pre> + +<p>As you will recall from the lesson on <a href="/en-US/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance">cascade and inheritance</a> where we discussed specificity, class selectors are more specific than element selectors, and so this is the value that applies. DevTools can help you find such issues, especially if the information is buried somewhere in a huge stylesheet.</p> + +<p><strong>Inspect the <code><em></code> with the class of <code>.special</code> and DevTools will show you that orange is the color that applies, and also shows you the <code>color</code> property applied to the em crossed out. You can now see that the class is overriding the element selector.</strong></p> + +<p><img alt="Selecting an em and looking at DevTools to see what is over-riding the color." src="https://mdn.mozillademos.org/files/16610/inspecting5-specificity.png" style="border-style: solid; border-width: 1px; height: 1161px; width: 2275px;"></p> + +<h2 id="Find_out_more_about_the_Firefox_DevTools">Find out more about the Firefox DevTools</h2> + +<p>There is a lot of information about the Firefox DevTools here on MDN. Take a look at the main <a href="/en-US/docs/Tools">DevTools section</a>, and for more detail on the things we have briefly covered in this lesson see <a href="/en-US/docs/Tools/Page_Inspector#How_to">The How To Guides</a>.</p> + +<h2 id="Debugging_problems_in_CSS">Debugging problems in CSS</h2> + +<p>DevTools can be a great help when solving CSS problems, so when you find yourself in a situation where CSS isn't behaving as you expect, how should you go about solving it? The following steps should help.</p> + +<h3 id="Take_a_step_back_from_the_problem">Take a step back from the problem</h3> + +<p>Any coding problem can be frustrating, especially CSS problems because you often don't get an error message to search for online to help with finding a solution. If you are becoming frustrated, take a step away from the issue for a while — go for a walk, grab a drink, chat to a co-worker, or work on some other thing for a while. Sometimes the solution magically appears when you stop thinking about the problem, and even if not, working on it when feeling refreshed will be much easier.</p> + +<h3 id="Do_you_have_valid_HTML_and_CSS">Do you have valid HTML and CSS?</h3> + +<p>Browsers expect your CSS and HTML to be correctly written, however browsers are also very forgiving and will try their best to display your webpages even if you have errors in the markup or stylesheet. If you have mistakes in your code the browser needs to make a guess at what you meant, and it might make a different decision to what you had in mind. In addition, two different browsers might cope with the problem in two different ways. A good first step therefore is to run your HTML and CSS through a validator, to pick up and fix any errors.</p> + +<ul> + <li><a href="https://jigsaw.w3.org/css-validator/">CSS Validator</a></li> + <li><a href="https://validator.w3.org/">HTML validator</a></li> +</ul> + +<h3 id="Is_the_property_and_value_supported_by_the_browser_you_are_testing_in">Is the property and value supported by the browser you are testing in?</h3> + +<p>Browsers simply ignore CSS they don't understand. If the property or value you are using is not supported by the browser you are testing in then nothing will break, but that CSS won't be applied. DevTools will generally highlight unsupported properties and values in some way. In the screenshot below the browser does not support the subgrid value of {{cssxref("grid-template-columns")}}.</p> + +<p><img alt="Image of browser DevTools with the grid-template-columns: subgrid crossed out as the subgrid value is not supported." src="https://mdn.mozillademos.org/files/16641/no-support.png" style="height: 397px; width: 1649px;"></p> + +<p>You can also take a look at the Browser compatibility tables at the bottom of each property page on MDN. These show you browser support for that property, often broken down if there is support for some usage of the property and not others. The below table shows the compat data for the {{cssxref("shape-outside")}} property.</p> + +<p>{{compat("css.shape-outside")}}</p> + +<h3 id="Is_something_else_overriding_your_CSS">Is something else overriding your CSS?</h3> + +<p>This is where the information you have learned about specificity will come in very useful. If you have something more specific overriding what you are trying to do, you can enter into a very frustrating game of trying to work out what. However, as described above, DevTools will show you what CSS is applying and you can work out how to make the new selector specific enough to override it.</p> + +<h3 id="Make_a_reduced_test_case_of_the_problem">Make a reduced test case of the problem</h3> + +<p>If the issue isn't solved by the steps above, then you will need to do some more investigating. The best thing to do at this point is to create something known as a reduced test case. Being able to "reduce an issue" is a really useful skill. It will help you find problems in your own code and that of your colleagues, and will also enable you to report bugs and ask for help more effectively.</p> + +<p>A reduced test case is a code example that demonstrates the problem in the simplest possible way, with unrelated surrounding content and styling removed. This will often mean taking the problematic code out of your layout to make a small example which only shows that code or feature.</p> + +<p>To create a reduced test case:</p> + +<ol> + <li>If your markup is dynamically generated — for example via a CMS — make a static version of the output that shows the problem. A code sharing site like <a href="https://codepen.io/">CodePen</a> is useful for hosting reduced test cases, as then they are accessible online and you can easily share them with colleagues. You could start by doing View Source on the page and copying the HTML into CodePen, then grab any relevant CSS and JavaScript and include it too. After that, you can check whether the issue is still evident.</li> + <li>If removing the JavaScript does not make the issue go away, don't include the JavaScript. If removing the JavaScript <em>does</em> make the issue go away, then remove as much JavaScript as you can, leaving in whatever causes the issue.</li> + <li>Remove any HTML that does not contribute to the issue. Remove components or even main elements of the layout. Again, try to get down to the smallest amount of code that still shows the issue.</li> + <li>Remove any CSS that doesn't impact the issue.</li> +</ol> + +<p>In the process of doing this, you may discover what is causing the problem, or at least be able to turn it on and off by removing something specific. It is worth adding some comments to your code as you discover things. If you need to ask for help, they will show the person helping you what you have already tried. This may well give you enough information to be able to search for likely sounding problems and workarounds.</p> + +<p>If you are still struggling to fix the problem then having a reduced test case gives you something to ask for help with, by posting to a forum, or showing to a co-worker. You are much more likely to get help if you can show that you have done the work of reducing the problem and identifying exactly where it happens, before asking for help. A more experienced developer might be able to quickly spot the problem and point you in the right direction, and even if not, your reduced test case will enable them to have a quick look and hopefully be able to offer at least some help.</p> + +<p>In the instance that your problem is actually a bug in a browser, then a reduced test case can also be used to file a bug report with the relevant browser vendor (e.g. on Mozilla's <a href="https://bugzilla.mozilla.org">bugzilla site</a>).</p> + +<p>As you become more experienced with CSS, you will find that you get faster at figuring out issues. However even the most experienced of us sometimes find ourselves wondering what on earth is going on. Taking a methodical approach, making a reduced test case, and explaining the issue to someone else will usually result in a fix being found.</p> + +<p>{{PreviousMenuNext("Learn/CSS/Building_blocks/Styling_tables", "Learn/CSS/Building_blocks/Organizing", "Learn/CSS/Building_blocks")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ol> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance">Cascade and inheritance</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors">CSS selectors</a> + <ul> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Type_Class_and_ID_Selectors">Type, class, and ID selectors</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Attribute_selectors">Attribute selectors</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Pseudo-classes_and_pseudo-elements">Pseudo-classes and pseudo-elements</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Combinators">Combinators</a></li> + </ul> + </li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/The_box_model">The box model</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Backgrounds_and_borders">Backgrounds and borders</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Handling_different_text_directions">Handling different text directions</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Overflowing_content">Overflowing content</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Values_and_units">Values and units</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Sizing_items_in_CSS">Sizing items in CSS</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Images_media_form_elements">Images, media, and form elements</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Styling_tables">Styling tables</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Debugging_CSS">Debugging CSS</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Organizing">Organizing your CSS</a></li> +</ol> diff --git a/files/ko/learn/css/building_blocks/handling_different_text_directions/index.html b/files/ko/learn/css/building_blocks/handling_different_text_directions/index.html new file mode 100644 index 0000000000..7282ef5793 --- /dev/null +++ b/files/ko/learn/css/building_blocks/handling_different_text_directions/index.html @@ -0,0 +1,147 @@ +--- +title: 텍스트 표시 방향 제어하기 +slug: Learn/CSS/Building_blocks/Handling_different_text_directions +translation_of: Learn/CSS/Building_blocks/Handling_different_text_directions +--- +<div>{{LearnSidebar}}{{PreviousMenuNext("Learn/CSS/Building_blocks/Backgrounds_and_borders", "Learn/CSS/Building_blocks/Overflowing_content", "Learn/CSS/Building_blocks")}}</div> + +<p>CSS 학습에서 지금까지 경험한 많은 속성과 값은 화면의 크기와 연결되어 있습니다. 예를 들어, 박스의 위, 오른쪽, 아래쪽 및 왼쪽에 테두리를 만듭니다. 이러한 실제 측정 기준은 가로로 표시되는 콘텐츠에 매우 깔끔하게 매핑되며, 기본적으로 웹은 오른쪽에서 왼쪽으로 쓰는 언어 (예: 아랍어) 보다 왼쪽에서 오른쪽으로 쓰는 언어 (예: 영어 또는 프랑스어) 를 더 잘 지원하는 경향이 있습니다.</p> + +<p>그러나 최근 몇 년 동안, CSS 는 오른쪽에서 왼쪽 뿐만 아니라 위에서 아래로 오는 콘텐츠 (예: 일본어) 를 포함하여 다른 내용의 방향성을 더 잘 지원하기 위해 발전했습니다 — 이러한 다른 방향을 <strong>쓰기 모드 (writing modes)</strong> 라고 합니다. 학습 과정을 진행하고 레이아웃 작업을 시작함에 따라 쓰기 모드에 대한 이해가 도움이 될 것이므로 지금 소개하겠습니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">전제조건:</th> + <td>기본 컴퓨터 활용 능력, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Installing_basic_software">기본 소프트웨어 설치</a>, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Dealing_with_files">파일 작업</a> 에 대한 기본 지식, HTML 기본 사항 (<a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">HTML 소개</a> 학습) 및 , CSS 작동 방식 이해 (<a href="/en-US/docs/Learn/CSS/First_steps">CSS 첫 번째 단계</a> 학습)</td> + </tr> + <tr> + <th scope="row">목적:</th> + <td>최신 CSS 에 대한 쓰기 모드의 중요성을 이해하기.</td> + </tr> + </tbody> +</table> + +<h2 id="쓰기_모드_writing_modes란_무엇인가">쓰기 모드 (writing modes)란 무엇인가?</h2> + +<p>CSS 쓰기 모드는 텍스트가 가로 또는 세로로 표시되는지 여부를 나타냅니다. {{cssxref("writing-mode")}} 속성을 사용하면 쓰기 모드에서 다른 쓰기 모드로 전환할 수 있습니다. 이를 위해 세로 쓰기 모드를 사용하는 언어로 작업할 필요는 없습니다 — 창의적 목적으로 레이아웃 일부의 쓰기 모드를 변경할 수도 있습니다.</p> + +<p>아래 예에서는 <code>writing-mode: vertical-rl</code> 를 사용하여 표시되는 제목이 있습니다. 이제 텍스트가 세로로 나타납니다. 세로 텍스트는 그래픽 디자인에서 일반적이며, 웹 디자인에서 보다 흥미로운 모양과 느낌을 추가할 수 있습니다.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/writing-modes/simple-vertical.html", '100%', 800)}}</p> + +<p><code><a href="/en-US/docs/Web/CSS/writing-mode">writing-mode</a></code> 속성에 가능한 세 가지 값은 다음과 같습니다:</p> + +<ul> + <li><code>horizontal-tb</code>: 블록의 표시 방향은 위에서 아래 입니다. 문장은 가로로 표시됩니다.</li> + <li><code>vertical-rl</code>: 블록의 표시 방향은 오른쪽에서 왼쪽입니다. 문장은 수직으로 표시됩니다.</li> + <li><code>vertical-lr</code>: 블록의 표시 방향은 왼쪽에서 오른쪽입니다. 문장은 수직으로 표시됩니다.</li> +</ul> + +<p>따라서 <code>writing-mode</code> 속성은 실제로 페이지에서 블록 수준 요소가 표시되는 방향을 설정합니다 — 위에서 아래로, 오른쪽에서 왼쪽으로 또는 왼쪽에서 오른쪽으로. 그러면 문장의 텍스트 방향이 지시됩니다.</p> + +<h2 id="쓰기_모드_와_블록_및_인라인_레이아웃">쓰기 모드 와 블록 및 인라인 레이아웃</h2> + +<p>우리는 이미 <a href="/en-US/docs/Learn/CSS/Building_blocks/The_box_model#Block_and_inline_boxes">블록 및 인라인 레이아웃</a> 과 일부는 블록 요소로 표시되고 다른 것은 인라인 요소로 표시된다는 사실에 대해 이미 논의했습니다. 위에서 설명한 것처럼 블록과 인라인은 실제 화면이 아니라 문서의 쓰기 모드와 연결되어 있습니다. 영어와 같이 텍스트를 가로로 표시하는 쓰기 모드를 사용하는 경우 블록은 페이지의 맨 위에서 아래로만 표시됩니다.</p> + +<p>예제를 보면 더 명확해집니다. 이 다음 예제에서는 제목과 단락을 포함하는 두 개의 박스가 있습니다. 첫 번째 쓰기 모드는 페이지 상단에서 하단으로 수평으로 표시되는 <code>writing-mode: horizontal-tb</code> 를 사용합니다. 두 번째 쓰기 모드는 세로로 오른쪽에서 왼쪽으로 표시되는 <code>writing-mode: vertical-rl</code> 를 사용합니다.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/writing-modes/block-inline.html", '100%', 1200)}}</p> + +<p>쓰기 모드를 전환하면, 블록 (block) 방향과 인라인 (inline) 방향을 변경합니다. <code>horizontal-tb</code> 쓰기 모드에서 블록 방향은 위에서 아래로 진행됩니다. <code>vertical-rl</code> 쓰기 모드에서 블록 방향은 오른쪽에서 왼쪽으로 수평으로 표시됩니다. 따라서 <strong>블록 크기</strong>는 항상 쓰기 모드에서 페이지에 표시되는 방향 블록입니다. <strong>인라인 크기</strong>는 항상 문장이 표시되는 방향입니다.</p> + +<p>이 그림은 가로 쓰기 모드에 있을 때 2 차원 모양을 보여줍니다.<img alt="Showing the block and inline axis for a horizontal writing mode." src="https://mdn.mozillademos.org/files/16574/horizontal-tb.png" style="height: 353px; width: 634px;"></p> + +<p>이 그림은 세로 쓰기 모드에서 2 차원 모양을 보여줍니다.</p> + +<p><img alt="Showing the block and inline axis for a vertical writing mode." src="https://mdn.mozillademos.org/files/16575/vertical.png" style="height: 472px; width: 406px;"></p> + +<p>CSS 레이아웃, 특히 최신 레이아웃 방법을 살펴보기 시작하면, 블록 및 인라인에 대한 이 아이디어가 매우 중요해 집니다. 나중에 다시 방문하겠습니다.</p> + +<h3 id="방향_Direction">방향 (Direction)</h3> + +<p>쓰기 모드 외에 텍스트 방향도 있습니다. 위에서 언급한 것처럼, 아랍어와 같은 일부 언어는 가로로 작성되지만, 오른쪽에서 왼쪽으로 작성됩니다. 이것은 창의적 의미에서 사용할 가능성이 있는 것이 아닙니다 — 단순히 오른쪽에 무언가를 정렬하려면 다른 방법이 있습니다 — 그러나 CSS 의 특성의 일부로 이것을 이해하는 것이 중요합니다. 웹은 왼쪽에서 오른쪽으로 표시되는 언어만을 위한 것이 아닙니다!</p> + +<p>쓰기 모드와 텍스트 방향이 변경될 수 있기 때문에, 최신 CSS 레이아웃 방법은 왼쪽과 오른쪽, 위와 아래를 참조하지 않습니다. 대신에 그들은 인라인과 블록이라는 아이디어와 함께 <em><strong>시작</strong> </em>과 <em><strong>끝</strong> </em>에 대해 이야기할 것입니다. 지금 그것에 대해 너무 걱정하지 말고 레이아웃을 살펴보기 시작할 때, 이러한 아이디어를 명심하십시오. CSS 에 대한 이해에 도움이 될 것입니다.</p> + +<h2 id="논리적_속성_및_값">논리적 속성 및 값</h2> + +<p>그러나 이 시점의 학습에서 쓰기 모드와 방향에 대해 이야기하는 이유는 우리가 이미 화면의 크기와 관련된 많은 속성을 보았고, 수평 쓰기 모드에 있을 때 가장 의미가 있기 때문입니다.</p> + +<p>두 개의 박스를 다시 살펴 보겠습니다 — 하나는 <code>horizontal-tb</code> 쓰기 모드이고 다른 하나는 <code>vertical-rl</code> 입니다. 이 두 박스 모두 {{cssxref("width")}} 를 제공했습니다. 박스가 세로 쓰기 모드일 때 여전히 너비가 있으며, 이로 인해 텍스트가 overflow 되는 것을 알 수 있습니다.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/writing-modes/width.html", '100%', 1200)}}</p> + +<p>이 시나리오에서 우리가 정말로 원하는 것은 쓰기 모드와 함께 높이와 너비를 본질적으로 바꾸는 것입니다. 세로 쓰기 모드인 경우 박스를 가로 쓰기 모드에서와 같이 블록 크기로 확장하려고 합니다.</p> + +<p>이를 쉽게하기 위해, CSS 는 최근에 매핑된 속성 세트를 개발했습니다. 이것들은 본질적으로 — <code>width</code> 및 <code>height</code> — 와 같은 물리적 속성을 <strong>논리적</strong> 또는 <strong>flow relative</strong> 버전으로 대체합니다.</p> + +<p>가로 쓰기 모드인 경우 <code>width</code> 에 매핑된 속성을 {{cssxref("inline-size")}} 라고 합니다 — 인라인의 크기를 나타냅니다. <code>height</code> 의 속성 이름은 {{cssxref("block-size")}} 이며 블록의 크기입니다. <code>width</code> 가 <code>inline-size</code> 로 대체된 아래 예에서 이것이 어떻게 작동하는지 볼 수 있습니다.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/writing-modes/inline-size.html", '100%', 1200)}}</p> + +<h3 id="논리적_마진_테두리_및_패딩_속성">논리적 마진, 테두리 및 패딩 속성</h3> + +<p>지난 두 가지 수업에서 CSS 박스 모델과 CSS 테두리에 대해 배웠습니다. 마진, 테두리 및 패딩 속성에는 {{cssxref("margin-top")}}, {{cssxref("padding-left")}} 및 {{cssxref("border-bottom")}} 과 같은 여러 물리적 속성 인스턴스가 있습니다. 너비와 높이에 대한 매핑과 같은 방식으로 이러한 속성에 대한 매핑도 있습니다.</p> + +<p><code>margin-top</code> 속성은 {{cssxref("margin-block-start")}} 에 매핑됩니다 — 이것은 항상 블록 크기의 시작에서 마진을 나타냅니다.</p> + +<p>{{cssxref("padding-left")}} 속성은 인라인 방향의 시작 부분에 적용되는 패딩 {{cssxref("padding-inline-start")}} 에 매핑됩니다. 이것은 쓰기 모드에서 문장이 시작되는 곳입니다. {{cssxref("border-bottom")}} 속성은 블록 크기의 끝의 경계인 {{cssxref("border-block-end")}} 에 매핑됩니다.</p> + +<p>아래에서 물리적 속성과 논리적 속성을 비교할 수 있습니다.</p> + +<p><strong><code>.box</code> 의 쓰기 모드 속성을 <code>vertical-rl</code> 로 전환하여 박스의 <code>writing-mode</code> 를 변경하면 물리적 속성이 물리적 방향과 연결되어 있는 반면, 논리적 속성은 쓰기 모드로 전환됩니다.</strong></p> + +<p><strong>또한 {{htmlelement("h2")}} 에 검은색 <code>border-bottom</code> 이 있음을 알 수 있습니다. 아래쪽 테두리가 항상 두 쓰기 모드에서 텍스트 아래로 이동하는 방법을 알아낼 수 있습니까?</strong></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/writing-modes/logical-mbp.html", '100%', 1200)}}</p> + +<p>모든 개별 테두리를 고려할 때 많은 속성이 있으며, <a href="/en-US/docs/Web/CSS/CSS_Logical_Properties">논리 속성 및 값</a> 에 대한 MDN 페이지에서 매핑된 속성을 모두 볼 수 있습니다.</p> + +<h3 id="논리적_값">논리적 값</h3> + +<p>지금까지 논리적 속성 이름을 살펴보았습니다. <code>top</code>, <code>right</code>, <code>bottom</code> 및 <code>left</code> 의 물리적 값을 취하는 속성도 있습니다 — 이러한 값에는 <code>block-start</code>, <code>inline-end</code>, <code>block-end</code> 및 <code>inline-start</code> 과 같은 논리값에 대한 매핑도 있습니다.</p> + +<p>예를 들어, 이미지를 왼쪽으로 띄워서 텍스트가 이미지를 감싸도록 할 수 있습니다. 아래 예와 같이 <code>left</code> 을 <code>inline-start</code> 으로 바꿀 수 있습니다.</p> + +<p><strong>이 예제에서 쓰기 모드를 <code>vertical-rl</code> 로 변경하여 이미지에 어떤 일이 발생하는지 확인하십시오. float 를 변경하려면 <code>inline-start</code> 를 <code>inline-end</code> 로 변경하십시오.</strong></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/writing-modes/float.html", '100%', 1200)}}</p> + +<p>여기에서는 쓰기 모드가 무엇이든 상관없이 논리 마진값을 사용하여 마진이 올바른 위치에 있는지 확인합니다.</p> + +<h3 id="물리적_또는_논리적_속성을_사용해야_합니까">물리적 또는 논리적 속성을 사용해야 합니까?</h3> + +<p>논리적 속성과 값은 물리적 속성보다 최신이므로, 브라우저에서만 최근에 구현되었습니다. 브라우저 지원이 얼마나 돌아가는지 보려면, MDN 의 속성 페이지를 확인할 수 있습니다. 여러 쓰기 모드를 사용하지 않는 경우, 지금은 실제 버전을 사용하는 것이 좋습니다. 그러나 궁극적으로 사람들은 flexbox 및 grid 와 같은 레이아웃 방법을 다루기 시작하면, 많은 의미가 있기 때문에 사람들이 대부분의 경우 논리적 버전으로 전환할 것으로 기대합니다.</p> + +<h2 id="요약">요약</h2> + +<p>이 학습에서 설명 개념은 CSS 에서 점점 중요해지고 있습니다. 블록과 인라인 방향에 대한 이해와 쓰기 모드의 변화에 따른 텍스트 방향의 변화는 앞으로 매우 유용할 것입니다. 가로 이외의 쓰기 모드를 사용하지 않아도 CSS 를 이해하는 데 도움이 됩니다.</p> + +<p>다음 학습에서는 CSS 의 overflow 를 자세히 살펴볼 것입니다.</p> + +<p>{{PreviousMenuNext("Learn/CSS/Building_blocks/Backgrounds_and_borders", "Learn/CSS/Building_blocks/Overflowing_content", "Learn/CSS/Building_blocks")}}</p> + +<h2 id="이번_단원에서는">이번 단원에서는</h2> + +<ol> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance">계단식 및 상속</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors">CSS 선택자</a> + <ul> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Type_Class_and_ID_Selectors">Type, class 및 ID 선택자</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Attribute_selectors">속성 선택자</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Pseudo-classes_and_pseudo-elements">Pseudo-classes 및 pseudo-elements</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Combinators">결합자</a></li> + </ul> + </li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/The_box_model">박스 모델</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Backgrounds_and_borders">배경 및 테두리</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Handling_different_text_directions">다른 텍스트 방향 처리</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Overflowing_content">콘텐츠 overflow</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Values_and_units">값 과 단위</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Sizing_items_in_CSS">CSS 에서 항목 크기 조정</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Images_media_form_elements">이미지, 미디어 및 양식 요소</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Styling_tables">표 스타일링</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Debugging_CSS">CSS 디버깅</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Organizing">CSS 정리</a></li> +</ol> diff --git a/files/ko/learn/css/building_blocks/images_media_form_elements/index.html b/files/ko/learn/css/building_blocks/images_media_form_elements/index.html new file mode 100644 index 0000000000..10945b103d --- /dev/null +++ b/files/ko/learn/css/building_blocks/images_media_form_elements/index.html @@ -0,0 +1,195 @@ +--- +title: '이미지, 미디어 및 양식 요소nts' +slug: Learn/CSS/Building_blocks/Images_media_form_elements +translation_of: Learn/CSS/Building_blocks/Images_media_form_elements +--- +<div>{{LearnSidebar}}{{PreviousMenuNext("Learn/CSS/Building_blocks/Sizing_items_in_CSS", "Learn/CSS/Building_blocks/Styling_tables", "Learn/CSS/Building_blocks")}}</div> + +<p>In this lesson we will take a look at how certain special elements are treated in CSS. Images, other media, and form elements behave a little differently in terms of your ability to style them with CSS than regular boxes. Understanding what is and isn't possible can save some frustration, and this lesson will highlight some of the main things that you need to know.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">전제조건:</th> + <td> + <p>기본 컴퓨터 활용 능력, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Installing_basic_software">기본 소프트웨어 설치</a>, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Dealing_with_files">파일 작업</a> 에 대한 기본 지식, HTML 기본 사항 (<a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">HTML 소개</a> 학습) 및 , CSS 작동 방식 이해 (<a href="/en-US/docs/Learn/CSS/First_steps">CSS 첫 번째 단계</a> 학습)</p> + </td> + </tr> + <tr> + <th scope="row">목적:</th> + <td>CSS 로 스타일을 지정할 때 일부 요소가 비정상적으로 동작하는 방식을 이해하기.</td> + </tr> + </tbody> +</table> + +<h2 id="대체_Replaced_요소">대체 (Replaced) 요소</h2> + +<p>이미지와 비디오는 <strong><a href="/en-US/docs/Web/CSS/Replaced_element">대체 요소</a></strong> 로 설명됩니다. 즉, CSS 는 이러한 요소의 내부 레이아웃에 영향을 줄 수 없으며 — 다른 요소중에서 페이지의 위치에만 영향을 줍니다. 그러나 우리가 볼 수 있듯이 CSS 는 이미지로 할 수 있는 다양한 일들이 있습니다.</p> + +<p>이미지 및 비디오와 같은 특정 대체 요소도 <strong>종횡비 (aspect ratio) </strong>를 갖는 것으로 설명됩니다. 이는 가로 (x) 및 세로 (y) 크기를 가지며, 기본적으로 파일의 고유 크기를 사용하여 표시됨을 의미합니다.</p> + +<h2 id="이미지_크기_조정">이미지 크기 조정</h2> + +<p>이 수업을 수행하여 이미 알고 있듯이 CSS 의 모든 것은 박스를 생성합니다. 이미지 파일의 고유 크기보다 작거나 큰 박스 안에 이미지를 배치하면, 박스보다 작게 나타나거나 박스가 overflow 됩니다. overflow 로 인해 발생하는 일에 대해 결정해야 합니다.</p> + +<p>아래 예에서는 크기가 200 픽셀인 두 개의 박스가 있습니다:</p> + +<ul> + <li>하나는 200 픽셀보다 작은 이미지를 포함합니다 — 이미지는 박스보다 작으며 이미지를 채우기 위해 늘어나지 않습니다.</li> + <li>다른 하나는 200 픽셀보다 커서 박스를 넘칩니다.</li> +</ul> + +<p>{{EmbedGHLiveSample("css-examples/learn/images/size.html", '100%', 1000)}}</p> + +<p>overflow 문제에 대해 우리는 무엇을 할 수 있습니까?</p> + +<p><a href="/en-US/docs/Learn/CSS/Building_blocks/Sizing_items_in_CSS">이전 수업</a> 에서 배운 것처럼 일반적인 기술은 이미지의 {{cssxref("max-width")}} 를 100% 로 만드는 것입니다. 이렇게하면 이미지가 박스보다 작지만 커질 수 없습니다. 이 기술은 <code><a href="/en-US/docs/Web/HTML/Element/video"><video></a></code> 또는 <code><a href="/en-US/docs/Web/HTML/Element/iframe"><iframe></a></code> 과 같은 다른 대체 요소와 함께 작동합니다.</p> + +<p><strong>위 예에서 <code><img></code> 요소에 <code>max-width: 100%</code> 를 추가하십시오. 작은 이미지는 변경되지 않지만, 큰 이미지는 박스에 맞게 작아집니다.</strong></p> + +<p>container 내부의 이미지에 대해 다른 선택을 할 수 있습니다. 예를 들어, 박스 크기를 완전히 덮을 수 있도록 이미지 크기를 조정할 수 있습니다.</p> + +<p>{{cssxref("object-fit")}} 속성이 도움이 될 수 있습니다. <code>object-fit</code> 를 사용할 때 대체 요소의 크기를 다양한 방식으로 박스에 맞게 조정할 수 있습니다.</p> + +<p>아래에서는 값 <code>cover</code> 를 사용하여 이미지의 크기를 줄이며, 화면 비율을 유지하여 박스를 깔끔하게 채웁니다. 종회비가 유지되면 이미지의 일부가 박스에 의해 잘립니다.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/images/object-fit.html", '100%', 1000)}}</p> + +<p><code>contain</code> 을 값으로 사용하면 이미지가 박스 안에 들어갈만큼 작아질 때까지 이미지가 축소됩니다. 박스와 종횡비가 다르면 "letterbox" 가 됩니다.</p> + +<p>박스를 채우지만 종횡비는 유지하지 않는 <code>fill</code> 값을 사용해 볼 수도 있습니다.</p> + +<h2 id="대체_요소_레이아웃">대체 요소 레이아웃</h2> + +<p>대체 요소에 다양한 CSS 레이아웃 기술을 사용하면, 다른 요소와 약간 다르게 동작할 수 있습니다. 예를 들어, flex 또는 grid 레이아웃에서 요소는 기본적으로 전체 영역을 채우기 위해 확장됩니다. 이미지가 늘어나지 않고 grid 영역 또는 flex container 의 시작 부분에 맞춰 정렬됩니다.</p> + +<p>아래 예에서 두 개의 열, 두 개의 행 grid container 가 있으며, 여기에는 네 개의 항목이 있습니다. 모든 <code><div></code> 요소는 배경색을 가지며 행과 열을 채우기 위해 확장됩니다. 그러나, 이미지가 늘어나지 않습니다.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/images/layout.html", '100%', 1000)}}</p> + +<p>이 수업을 순서대로 따르는 경우 레이아웃을 아직 보지 않았을 수 있습니다. 대체 요소는 grid 또는 flex 레이아웃의 일부가 될 때, 기본 동작이 서로 다르다는 점을 유념해 주십시오. 기본적으로 배치로 인해 이상하게 늘어나지 않도록 하기 위해서입니다.</p> + +<p>grid 셀을 채우도록 이미지를 늘리려면, 다음과 같은 작업을 수행해야 합니다:</p> + +<pre class="brush: css">img { + width: 100%; + height: 100%; +}</pre> + +<p>그러나 이것은 이미지를 늘릴 것이기 때문에, 아마 당신이 하고 싶지 않을 것입니다.</p> + +<h2 id="양식_Form_요소">양식 (Form) 요소</h2> + +<p>CSS 로 스타일링 할 때, 양식 요소는 까다로운 문제가 될 수 있으며 <a href="/en-US/docs/Learn/Forms">웹 양식 모듈</a> 에는 약식 요소의 까다로운 측면에 대한 자세한 안내서가 포함되어 있습니다. 이 기사에서 강조할 가치가 있는 몇 가지 기본 사항이 있습니다.</p> + +<p><code><a href="/en-US/docs/Web/HTML/Element/input"><input></a></code> 요소를 통해 많은 양식 컨트롤이 페이지에 추가됩니다 — 텍스트 입력과 같은 간단한 양식 필드를 정의하고 색상 및 날짜 선택자와 같은 HTML5 에 추가된 보다 복잡한 필드를 통해 정의합니다. 여러줄로 된 텍스트 입력을 위한 <code><a href="/en-US/docs/Web/HTML/Element/textarea"><textarea></a></code> 와 같은 일부 추가 요소와 <code><a href="/en-US/docs/Web/HTML/Element/fieldset"><fieldset></a></code> 및 <code><a href="/en-US/docs/Web/HTML/Element/legend"><legend></a></code> 와 같은 양식의 일부를 포함하고 레이블을 지정하는 데 사용되는 요소가 있습니다.</p> + +<p>HTML5 에는 또한 웹 개발자가 어떤 필드가 필요한지, 심지어 입력해야하는 콘텐츠 유형을 표시할 수 있는 속성이 포함되어 있습니다. 사용자가 예기치 않은 것을 입력하거나 필수 필드를 비워두면, 브라우저에 오류 메시지가 표시될 수 있습니다. 다른 브라우저는 이러한 항목에 대해 얼마나 많은 스타일과 사용자 정의가 허용되는지에 일관성이 없습니다.</p> + +<h3 id="텍스트_입력_요소_스타일링">텍스트 입력 요소 스타일링</h3> + +<p><code><input type="text"></code> 와 같은 텍스트 입력을 허용하는 요소, <code><input type="email"></code>, 과 같은 특정 유형 및 <code><textarea></code> 요소는 스타일이 매우 쉽고 다른 박스처럼 동작하는 경향이 있습니다. 귀하의 페이지에 이러한 요소의 기본 스타일은 사용자가 사이트를 방문하는 운영체제 및 브라우저에 따라 다릅니다.</p> + +<p>아래 예에서는 CSS 를 사용하여 일부 텍스트 입력의 스타일을 지정했습니다 — 테두리, 마진 및 패딩과 같은 항목이 모두 예상대로 적용되는 것을 볼 수 있습니다. 속성 선택자를 사용하여 다양한 입력 유형을 대상으로 하고 있습니다. 테두리를 조정하고, 필드에 배경색을 추가하고, 글꼴 및 패딩을 변경하여 이 양식의 모양을 변경하십시오.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/images/form.html", '100%', 1000)}}</p> + +<div class="blockIndicator warning"> +<p><strong>중요</strong>: 양식 요소의 스타일을 변경할 때 양식 요소임을 사용자에게 확실히 알 수 있도록 주의해야 합니다. 테두리와 배경이 없는 양식 입력을 작성할 수 있습니다. 이 입력 양식은 주변 내용과 거의 구분할 수 없습니다. 이로 인해 인식하고 채우기가 매우 어려워집니다.</p> +</div> + +<p>이 과정의 HTML 부분에서 <a href="/en-US/docs/Learn/Forms/Styling_web_forms">양식 스타일</a> 에 대한 강의에서 설명한대로, 보다 복잡한 입력 유형 중 많은 부분이 운영체제에서 렌더링되며 스타일에 액세스할 수 없습니다. 따라서 항상 방문자마다 양식이 크게 달라지고 여러 브라우저에서 복잡한 양식을 테스트한다고 가정해야합니다.</p> + +<h3 id="상속_과_양식_요소">상속 과 양식 요소</h3> + +<p>일부 브라우저에서 양식 요소는 기본적으로 글꼴 스타일을 상속하지 않습니다. 따라서 양식 필드가 본문 또는 상위 요소에 정의된 글꼴을 사용하도록 하려면, 이 규칙을 CSS 에 추가해야 합니다.</p> + +<pre class="brush: css"><code>button, +input, +select, +textarea { + font-family : inherit; + font-size : 100%; +} </code></pre> + +<h3 id="양식_요소_및_박스_크기_조정">양식 요소 및 박스 크기 조정</h3> + +<p>여러 브라우저 양식 요소는 서로 다른 위젯에 다른 박스 크기 조정 규칙을 사용합니다. <a href="/en-US/docs/Learn/CSS/Building_blocks/The_box_model">박스 모델 학습</a> 에서 <code>box-sizing</code> 속성에 대해 학습했으며 양식을 스타일링할 때 이 지식을 사용하여 양식 요소에서 너비와 높이를 설정할 때 일관된 경험을 보장할 수 있습니다.</p> + +<p>일관성을 유지하려면 모든 요소에서 마진과 패딩을 <code>0</code> 으로 설정한 다음 특정 컨트롤을 스타일링할 때 다시 마진을 추가하는 것이 좋습니다.</p> + +<pre class="brush: css"><code>button, +input, +select, +textarea { + box-sizing: border-box; + padding: 0; + margin: 0; +}</code></pre> + +<h3 id="다른_유용한_설정">다른 유용한 설정</h3> + +<p>위에서 언급한 규칙 외에도 <code><textarea></code> 에서 <code>overflow: auto</code> 를 설정하여 스크롤 막대가 필요하지 않은 경우 IE 에 스크롤 막대가 표시되지 않도록 설정해야 합니다:</p> + +<pre class="brush: css">textarea { + overflow: auto; +}</pre> + +<h3 id="모든_것을_재설정_으로_통합">모든 것을 "재설정" 으로 통합</h3> + +<p>마지막 단계로, 위에서 설명한 다양한 속성을 다음 "양식 재설정" 으로 마무리하여 일관된 작업 기반을 제공할 수 있습니다. 여기에는 마지막 세 섹션에서 언급한 모든 항목이 포함됩니다:</p> + +<pre class="brush: css"><code>button, +input, +select, +textarea { + font-family: inherit; + font-size: 100%; + box-sizing: border-box; + padding: 0; margin: 0; +} + +textarea { + overflow: auto; +} </code></pre> + +<div class="blockIndicator note"> +<p><strong>참고</strong>: Normalizing 스타일 시트는 많은 개발자가 모든 프로젝트에 사용할 일련의 기본 스타일을 작성하는 데 사용됩니다. 일반적으로 이것들은 위에서 설명한 것과 비슷한 기능을 수행하므로, CSS 에 대한 작업을 수행하기 전에 브라우저마다 다른것이 일관된 기본값으로 설정되어 있는지 확인하십시오. 브라우저는 일반적으로 과거보다 일관성이 높기 때문에, 예전만큼 중요하지 않습니다. 그러나 하나의 예를 살펴보려면 많은 프로젝트에서 기본으로 사용되는 매우 인기있는 스타일 시트인 <a href="http://necolas.github.io/normalize.css/">Normalize.css</a> 를 확인하십시오.</p> +</div> + +<p>스타일링 양식에 대한 자세한 내용은 이 안내의 HTML 섹션에 있는 두 기사를 살펴보십시오.</p> + +<ul> + <li><a href="/en-US/docs/Learn/Forms/Styling_web_forms">웹 양식 스타일링</a></li> + <li><a href="/en-US/docs/Learn/Forms/Advanced_form_styling">고급 양식 스타일링</a></li> +</ul> + +<h2 id="요약">요약</h2> + +<p>이 수업에서는 CSS 에서 이미지, 미디어 및 기타 특이한 요소로 작업할 때 발생할 수 있는 몇 가지 차이점을 강조했습니다. 다음 기사에서는 HTML 표의 스타일을 지정해야할 때 유용한 몇 가지 팁을 살펴보겠습니다.</p> + +<p>{{PreviousMenuNext("Learn/CSS/Building_blocks/Sizing_items_in_CSS", "Learn/CSS/Building_blocks/Styling_tables", "Learn/CSS/Building_blocks")}}</p> + +<h2 id="이번_강의에서는">이번 강의에서는</h2> + +<ol> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance">계단식 및 상속</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors">CSS 선택자</a> + <ul> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Type_Class_and_ID_Selectors">Type, class 및 ID 선택자</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Attribute_selectors">속성 선택자</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Pseudo-classes_and_pseudo-elements">Pseudo-classes 및 pseudo-elements</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Combinators">결합자</a></li> + </ul> + </li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/The_box_model">박스 모델</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Backgrounds_and_borders">배경 및 테두리</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Handling_different_text_directions">다른 텍스트 방향 처리</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Overflowing_content">콘텐츠 overflow</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Values_and_units">값 과 단위</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Sizing_items_in_CSS">CSS 에서 항목 크기 조정</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Images_media_form_elements">이미지, 미디어 및 양식 요소</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Styling_tables">표 스타일링</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Debugging_CSS">CSS 디버깅</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Organizing">CSS 정리</a></li> +</ol> diff --git a/files/ko/learn/css/building_blocks/index.html b/files/ko/learn/css/building_blocks/index.html new file mode 100644 index 0000000000..aa2d21c448 --- /dev/null +++ b/files/ko/learn/css/building_blocks/index.html @@ -0,0 +1,90 @@ +--- +title: CSS 구성 블록 +slug: Learn/CSS/Building_blocks +tags: + - Beginner + - CSS + - Learn + - NeedsTranslation + - TopicStub + - building blocks +translation_of: Learn/CSS/Building_blocks +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">이 강의에서는 <a href="/en-US/docs/Learn/CSS/First_steps">CSS 첫 번째 단계</a> 가 중단된 부분을 처리합니다 — 이제 언어와 구문에 익숙해졌으며, 약간 더 깊이 익힐 때가 되었을 때, 이를 사용하는 기본적인 경험을 얻었습니다. 이 과목에서는 계단식 및 상속, 사용 가능한 모든 선택자 유형, 단위 크기 조정, 배경 및 테두리 스타일 지정, 디버깅 등을 살펴 봅니다.</p> + +<p class="summary">여기에서의 목표는 <a href="/en-US/docs/Learn/CSS/Styling_text">텍스트 스타일</a> 및 <a href="/en-US/docs/Learn/CSS/CSS_layout">CSS 레이아웃</a> 과 같은 보다 구체적인 분야로 이동하기 전에 유능한 CSS 를 작성하기 위한 도구를 제공하고 모든 필수 이론을 이해하도록 돕는 것입니다.</p> + +<h2 id="전제_조건">전제 조건</h2> + +<p>이 과목을 시작하기 전에 다음이 있어야 합니다:</p> + +<ol> + <li>컴퓨터 사용 및 수동적으로 웹을 사용하는 것 (즉, 보기기만 하고 콘텐츠를 소비하는 것.) 에 대한 기본적인 친숙성.</li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web/Installing_basic_software">기본 소프트웨어 설치</a> 에 설명 된대로 기본 작업 환경과 <a href="https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web/Dealing_with_files">파일 처리</a> 에 설명 된대로 파일 작성 및 관리 방법에 대한 이해.</li> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">HTML 소개</a> 과목에서 설명한 HTML 에 대한 기본적인 친숙성.</li> + <li><a href="/en-US/docs/Learn/CSS/First_steps">CSS 첫 번째 단계</a> 과목에서 논의된 CSS 의 기본 사항에 대한 이해.</li> +</ol> + +<div class="note"> +<p><strong>참고</strong>: 자신의 파일을 만들 수 없는 컴퓨터/태블릿/기타 장치에서 작업하는 경우, <a href="http://jsbin.com/">JSBin</a> 또는 <a href="https://thimble.mozilla.org/">Thimble</a> 와 같은 온라인 코딩 프로그램에서 대부분의 코드 예제를 시험해 볼 수 있습니다.</p> +</div> + +<h2 id="안내">안내</h2> + +<p>이 강의에서는 CSS 언어의 가장 중요한 부분을 다루는 다음 기사가 포함되어 있습니다. 그 과정에서 당신은 이해력을 시험할 수 있도록 하기 위해 많은 연습을 하게 될 것입니다.</p> + +<dl> + <dt><a href="/en-US/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance">계단식 (cascade) 및 상속 (inheritance)</a></dt> + <dd>이번 수업의 목적은 CSS 가 HTML 에 적용되는 방법과 충돌을 해결하는 방법을 제어하는 CSS 의 가장 기본적인 개념인 — 계단식, 우선 순위 및 상속 — 에 대한 이해를 발전시키는 것입니다.</dd> + <dt><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors">CSS 선택자</a></dt> + <dd>사용 가능한 다양한 CSS 선택자가 있으며, 스타일을 지정할 요소를 선택할 때 세밀한 정밀도를 허용합니다. 이 기사와 하위 기사에서는 다양한 유형을 자세히 살펴보고 작동 방식을 살펴 보겠습니다. 하위 기사는 다음과 같습니다: + <ul> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Type_Class_and_ID_Selectors">Type, class 및 ID 선택자</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Attribute_selectors">속성 선택자</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Pseudo-classes_and_pseudo-elements">Pseudo-classes 및 pseudo-elements</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Combinators">결합자 (combinators)</a></li> + </ul> + </dd> + <dt><a href="/en-US/docs/Learn/CSS/Building_blocks/The_box_model">박스 모델</a></dt> + <dd>CSS 의 모든 것에는 주위에 박스가 있으며, 이러한 박스를 이해하는 것은 CSS 를 사용하여 레이아웃을 만들거나 다른 항목과 항목을 정렬하는 데 중요합니다. 이 수업에서는 CSS <em><strong>박스 모델</strong> </em>을 제대로 살펴보고, 작동 방식 및 관련 용어를 이해하여 보다 복잡한 레이아웃 작업으로 넘어갈 수 있습니다.</dd> + <dt><a href="/en-US/docs/Learn/CSS/Building_blocks/Backgrounds_and_borders">배경 및 테두리</a></dt> + <dd>이번 수업에서는 CSS 배경과 테두리로 할 수 있는 창의적인 작업을 살펴 보겠습니다. 그라데이션 (gradients), 배경 이미지 및 둥근 테두리를 추가하는 경우, 배경과 테두리는 CSS 의 많은 스타일 질문에 대한 답입니다.</dd> + <dt><a href="/en-US/docs/Learn/CSS/Building_blocks/Handling_different_text_directions">다른 텍스트 방향 처리</a></dt> + <dd>최근 몇 년 동안, CSS 는 오른쪽에서 왼쪽으로 뿐만 아니라, 위에서 아래로 (일본어와 같은) 내용을 포함하여 서로 다른 내용의 방향성을 더 잘 지원하기 위해 발전했습니다 — 이러한 다른 방향을 <strong>쓰기 모드 (writing modes)</strong> 라고 합니다. 학습 과정을 진행하고 레이아웃 작업을 시작하면 쓰기 모드에 대한 이해가 도움이 되므로 이 기사에서 소개합니다.</dd> + <dt><a href="/en-US/docs/Learn/CSS/Building_blocks/Overflowing_content">콘텐츠 Overflow</a></dt> + <dd>이 수업에서는 CSS 의 또 다른 중요한 개념인 — <strong>overflow</strong> 를 살펴 봅니다. Overflow 는 박스 안에 편안하게 담기에는 너무 많은 내용이 있을 때 발생합니다. 이 안내서에서는 내용과 관리 방법에 대해 설명합니다.</dd> + <dt><a href="/en-US/docs/Learn/CSS/Building_blocks/Values_and_units">CSS 값 과 단위</a></dt> + <dd>CSS 에 사용된 모든 속성에는 해당 속성에 허용되는 값이 있습니다. 이 수업에서는 가장 일반적인 값과 사용 단위를 살펴 보겠습니다.</dd> + <dt><a href="/en-US/docs/Learn/CSS/Building_blocks/Sizing_items_in_CSS">CSS 에서 항목 크기 조정</a></dt> + <dd>지금까지 다양한 수업에서는 CSS 를 사용하여 웹 페이지의 항목 크기를 조정하는 여러 가지 방법을 살펴 보았습니다. 디자인의 다양한 기능이 얼마나 큰지 이해하는 것이 중요하며, 이 수업에서는 CSS 를 통해 요소의 크기를 결정하는 다양한 방법을 요약하고 크기 조정과 관련하여 향후 도움이 될 몇 가지 용어를 정의합니다.</dd> + <dt><a href="/en-US/docs/Learn/CSS/Building_blocks/Images_media_form_elements">이미지, 미디어 및 양식 요소</a></dt> + <dd>이 수업에서는 CSS 에서 특정 특수 요소를 처리하는 방법을 살펴 봅니다. 이미지, 기타 미디어 및 양식 요소는 일반 박스와 CSS 로 스타일을 지정할 수 있다는 점에서 약간 다르게 작동합니다. 무엇이 가능하고 불가능한지를 이해하면, 약간의 좌절감을 줄일 수 있으며, 이 수업에서는 알아야 할 주요 사항을 중점적으로 다룹니다.</dd> + <dt><a href="/en-US/docs/Learn/CSS/Building_blocks/Styling_tables">표 스타일링</a></dt> + <dd>HTML 표 스타일링은 세계에서 가장 매력적인 일이 아니지만, 때로는 우리 모두가 해야할 일입니다. 이 기사에서는 특정 표 스타일링 기술을 강조 표시하여 HTML 표를 보기 좋게 만드는 방법에 대한 안내서를 제공합니다.</dd> + <dt><a href="/en-US/docs/Learn/CSS/Building_blocks/Debugging_CSS">CSS 디버깅</a></dt> + <dd>때로는 CSS 를 작성 할 때 CSS 가 예상 한 대로 동작하지 않는 문제가 발생합니다. 이 기사에서는 CSS 문제를 디버깅하는 방법에 대한 지침을 제공하고, 모든 최신 브라우저에 포함된 개발도구 (DevTools) 가 진행중인 작업을 찾는 데 어떻게 도움이 되는지 보여줍니다.</dd> + <dt><a href="/en-US/docs/Learn/CSS/Building_blocks/Organizing">CSS 정리</a></dt> + <dd>더 큰 스타일 시트와 큰 프로젝트에서 작업을 시작하면 큰 CSS 파일을 유지 관리하는 것이 어려울 수 있습니다. 이 기사에서는 CSS 를 쉽게 유지 관리 할 수 있도록 작성하는 몇 가지 모범 사례와 유지 관리를 개선하기 위해 다른 사용자가 사용하는 해결책을 간략하게 살펴 보겠습니다.</dd> +</dl> + +<h2 id="평가">평가</h2> + +<p>CSS 기술을 테스트하고 싶습니까? 다음 평가는 위 안내서에서 다루는 CSS 에 대한 이해를 테스트 합니다.</p> + +<dl> + <dt><a href="/en-US/docs/Learn/CSS/Introduction_to_CSS/Fundamental_CSS_comprehension">기본 CSS 이해</a></dt> + <dd>이 평가는 기본적인 구문, 선택자, 우선 순위, 박스 모델 등에 대한 이해를 테스트 합니다.</dd> + <dt><a href="/en-US/docs/Learn/CSS/Styling_boxes/Creating_fancy_letterheaded_paper">멋진 편지지 만들기</a></dt> + <dd>올바른 인상을 남기고 싶다면, 멋진 편지지에 편지를 쓰는 것이 정말 좋습니다. 이 평가에서는 이러한 모양을 달성하기 위해 온라인 템플릿을 작성해야 합니다.</dd> + <dt><a href="/en-US/docs/Learn/CSS/Styling_boxes/A_cool_looking_box">멋진 박스</a></dt> + <dd>여기에서는 배경 및 테두리 스타일을 사용하여 눈길을 끄는 박스를 만드는 방법을 연습합니다.</dd> +</dl> + +<h2 id="참고_항목">참고 항목</h2> + +<dl> + <dt><a href="/en-US/docs/Learn/CSS/Building_blocks/Advanced_styling_effects">고급 스타일링 효과</a></dt> + <dd>이 기사는 박스 그림자, blend modes 및 필터 와 같은 흥미로운 고급 스타일링 기능에 대한 소개를 제공하는 트릭 박스 역할을 합니다.</dd> +</dl> diff --git a/files/ko/learn/css/building_blocks/organizing/index.html b/files/ko/learn/css/building_blocks/organizing/index.html new file mode 100644 index 0000000000..a80c5cb17d --- /dev/null +++ b/files/ko/learn/css/building_blocks/organizing/index.html @@ -0,0 +1,350 @@ +--- +title: CSS 구성 +slug: Learn/CSS/Building_blocks/Organizing +translation_of: Learn/CSS/Building_blocks/Organizing +--- +<div>{{LearnSidebar}}{{PreviousMenu("Learn/CSS/Building_blocks/Debugging_CSS", "Learn/CSS/Building_blocks")}}</div> + +<p>더 큰 스타일 시트와 큰 프로젝트에서 작업을 시작하면 큰 CSS 파일을 유지 관리하는 것이 어려울 수 있습니다. 이 기사에서는 CSS 를 쉽게 유지 관리할 수 있도록 작성하는 몇 가지 모범 사례와 유지 관리성을 개선하기 위해, 다른 사용자가 사용하는 해결책을 간략하게 살펴보겠습니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">전제조건:</th> + <td>기본 컴퓨터 활용 능력, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Installing_basic_software">기본 소프트웨어 설치</a>, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Dealing_with_files">파일 작업</a> 에 대한 기본 지식, HTML 기본 사항 (<a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">HTML 소개</a> 학습) 및 , CSS 작동 방식 이해 (<a href="/en-US/docs/Learn/CSS/First_steps">CSS 첫 번째 단계</a> 학습)</td> + </tr> + <tr> + <th scope="row">목적:</th> + <td>스타일 시트 구성을 위한 몇 가지 팁과 모범사례를 배우고, CSS 구성 및 팀 작업에 도움이 되는 일반적인 사용법의 이름 지정 규칙 및 도구에 대해 알아보기.</td> + </tr> + </tbody> +</table> + +<h2 id="CSS_를_깔끔하게_유지하는_팁">CSS 를 깔끔하게 유지하는 팁</h2> + +<p>다음은 스타일 시트를 체계적이고 깔끔하게 유지하는 방법에 대한 일반적인 제안입니다.</p> + +<h3 id="프로젝트에_코딩_스타일_가이드라인이_있습니다">프로젝트에 코딩 스타일 가이드라인이 있습니다?</h3> + +<p>기존 프로젝트에서 팀과 함께 작업하는 경우, 가장 먼저 확인해야 할 것은 프로젝트에 CSS 에 대한 기존 스타일 가이드라인이 있는지 여부입니다. 팀 스타일 안내는 항상 개인 취향보다 우선합니다. 일을 하는 옳고 그른 방법은 없지만, 일관성이 중요합니다.</p> + +<p>예를 들어, <a href="/en-US/docs/MDN/Contribute/Guidelines/Code_guidelines/CSS">MDN code 예제에 대한 CSS 지침</a> 을 살펴보십시오.</p> + +<h3 id="일관성_유지">일관성 유지</h3> + +<p>프로젝트 규칙을 설정하거나 단독으로 작업하는 경우, 가장 중요한 것은 일관성을 유지하는 것입니다. 일관성은 class 에 동일한 이름 지정 규칙 사용, 색상을 설명하는 한 가지 방법을 선택하거나, 일관된 형식을 유지하는 등의 모든 종류의 방식으로 적용할 수 있습니다 (예: 탭이나 공백을 사용하여 코드를 들여쓰기 하시겠습니까? 공백은 몇 칸입니까?)</p> + +<p>규칙을 항상 준수하면 일부 결정이 이미 내려졌기 때문에, CSS 를 작성할 때 필요한 정신적 부담이 줄어듭니다.</p> + +<h3 id="읽기_쉬운_CSS_서식">읽기 쉬운 CSS 서식</h3> + +<p>CSS 형식을 볼 수 있는 몇 가지 방법이 있습니다. 일부 개발자는 다음과 같이 모든 규칙을 한 라인에 넣습니다:</p> + +<pre class="brush: css">.box { background-color: #567895; } +h2 { background-color: black; color: white; }</pre> + +<p>다른 개발자는 모든 것을 새로운 라인으로 나누는 것을 선호합니다:</p> + +<pre class="brush: css">.box { + background-color: #567895; +} + +h2 { + background-color: black; + color: white; +}</pre> + +<p>CSS 는 어떤 것을 사용하든 상관없습니다. 개인적으로 각 속성과 값 쌍을 새 라인에 추가하는 것이 더 읽기 쉽습니다.</p> + +<h3 id="CSS_주석_추가">CSS 주석 추가</h3> + +<p>CSS 에 주석을 추가하면 향후 개발자가 CSS 파일을 처리하는 데 도움이 되지만, 휴식 후 프로젝트에 다시 참여할 때도 도움이 됩니다.</p> + +<pre class="brush: css">/* 이것은 주석입니다 +여러 라인으로 구분할 수 있습니다. */</pre> + +<p>유용한 팁은 또한 스타일 시트의 논리 섹션 사이에 주석 블록을 추가하여 스캔할 때 다른 섹션을 신속하게 찾도록 도와주거나, CSS 의 해당 부분으로 바로 이동할 수 있는 정보를 제공하는 것이 좋습니다. 코드에 나타나지 않는 문자열을 사용하는 경우, 검색하여 섹션 간을 이동할 수 있습니다 — 아래에서 <code>||</code> 를 사용했습니다.</p> + +<pre class="brush: css">/* || 일반적인 스타일 */ + +... + +/* || Typography */ + +... + +/* || Header 및 Main Navigation */ + +... + +</pre> + +<p>CSS 의 모든 사항에 대해 일일이 설명할 필요는 없습니다. 대부분 따로 설명이 필요없기 때문입니다. 여러분이 언급해야 할 것은 특정한 이유로 결정한 것들입니다.</p> + +<p>오래된 브라우저 비 호환성을 피하기 위해 CSS 속성을 특정 방식으로 사용했을 수 있습니다. 예를 들면 다음과 같습니다:</p> + +<pre class="brush: css">.box { + background-color: red; /* 그라데이션을 지원하지 않는 이전 브라우저의 대비책 */ + background-image: linear-gradient(to right, #ff0000, #aa0000); +} +</pre> + +<p>아마도 여러분은 무언가를 성취하기 위해 자습서를 따랐을 것입니다. 그리고 CSS 는 약간 눈에 띄지 않습니다. 이 경우, 여러분은 주석에 자습서의 URL 을 추가할 수 있습니다. 1년 정도 지나고 이 프로젝트로 돌아왔을 때 자신에게 감사할 것입니다. 그에 대한 훌륭한 자습서가 있었음을 모호하게 기억할 수 있습니다. 그러나 어디에 있습니까?</p> + +<h3 id="Create_logical_sections_in_your_stylesheet">Create logical sections in your stylesheet</h3> + +<p>It is a good idea to have all of the common styling first in the stylesheet. This means all of the styles which will generally apply unless you do something special with that element. You will typically have rules set up for:</p> + +<ul> + <li><code>body</code></li> + <li><code>p</code></li> + <li><code>h1</code>, <code>h2</code>, <code>h3</code>, <code>h4</code>, <code>h5</code></li> + <li><code>ul</code> and <code>ol</code></li> + <li>The <code>table</code> properties</li> + <li>Links</li> +</ul> + +<p>In this section of the stylesheet we are providing default styling for the type on the site, setting up a default style for data tables and lists and so on.</p> + +<pre class="brush: css">/* || GENERAL STYLES */ + +body { ... } + +h1, h2, h3, h4 { ... } + +ul { ... } + +blockquote { ... } +</pre> + +<p>After this section we could define a few utility classes, for example a class that removes the default list style for lists we're going to display as flex items or in some other way. If you have a few things you know you will want to apply to lots of different elements, they can come in this section.</p> + +<pre class="brush: css">/* || UTILITIES */ + +.nobullets { + list-style: none; + margin: 0; + padding: 0; +} + +... + +</pre> + +<p>Then we can add everything that is used sitewide. That might be things like the basic page layout, the header, navigation styling, and so on.</p> + +<pre class="brush: css">/* || SITEWIDE */ + +.main-nav { ... } + +.logo { ... } +</pre> + +<p>Finally we will include CSS for specific things, broken down by the context, page or even component in which they are used.</p> + +<pre class="brush: css">/* || STORE PAGES */ + +.product-listing { ... } + +.product-box { ... } +</pre> + +<p>By ordering things in this way, we at least have an idea in which part of the stylesheet we will be looking for something that we want to change.</p> + +<h3 id="Avoid_overly-specific_selectors">Avoid overly-specific selectors</h3> + +<p>If you create very specific selectors you will often find that you need to duplicate chunks of your CSS to apply the same rules to another element. For example, you might have something like the below selector, which applies the rule to a <code><p></code> with a class of <code>box</code> inside an <code><article></code> with a class of <code>main</code>.</p> + +<pre class="brush: css">article.main p.box { + border: 1px solid #ccc; +}</pre> + +<p>If you then wanted to apply the same rules to something outside of <code>main</code>, or to something other than a <code><p></code>, you would have to add another selector to these rules or create a whole new ruleset. Instead, you could create a class called <code>box</code> and apply that anywhere.</p> + +<pre class="brush: css">.box { + border: 1px solid #ccc; +}</pre> + +<p>There will be times when making something more specific makes sense, however this will generally be an exception rather than usual practice.</p> + +<h3 id="Break_large_stylesheets_into_multiple_smaller_ones">Break large stylesheets into multiple smaller ones</h3> + +<p>In particular in cases where you have very different styles for distinct parts of the site, you might want to have a stylesheet that includes all the global rules and then smaller ones that include the specific rules needed for those sections. You can link to multiple stylesheets from one page, and the normal rules of the cascade apply, with rules in stylesheets linked later coming after rules in stylesheets linked earlier.</p> + +<p>For example, we might have an online store as part of the site, with a lot of CSS used only for styling the product listings and forms needed for the store. It would make sense to have those things in a different stylesheet, only linked to on store pages.</p> + +<p>This can make it easier to keep your CSS organised, and also means that if multiple people are working on the CSS you will have fewer situations where two people need to work on the same stylesheet at once, leading to conflicts in source control.</p> + +<h2 id="Other_tools_that_can_help">Other tools that can help</h2> + +<p>CSS itself doesn't have much in the way of in-built organisation, therefore you need to do the work to create consistency and rules around how you write CSS. The web community has also developed various tools and approaches that can help you to manage larger CSS projects. As they may be helpful for you to investigate, and you are likely to come across these things when working with other people, we've included a short guide to some of these.</p> + +<h3 id="CSS_methodologies">CSS methodologies</h3> + +<p>Instead of needing to come up with your own rules for writing CSS, you may benefit from adopting one of the approaches already designed by the community and tested across many projects. These methodologies are essentially CSS coding guides that take a very structured approach to writing and organising CSS. Typically they tend to result in more verbose use of CSS than you might have if you wrote and optimised every selector to a custom set of rules for that project.</p> + +<p>However, you do gain a lot of structure by adopting one and, as many of these systems are very widely used, other developers are more likely to understand the approach you are using and be able to write their CSS in the same way, rather than having to work out your own personal methodology from scratch.</p> + +<h4 id="OOCSS">OOCSS</h4> + +<p>Most of the approaches that you will encounter owe something to the concept of Object Oriented CSS (OOCSS), an approach made popular by <a href="https://github.com/stubbornella/oocss/wiki">the work of Nicole Sullivan</a>. The basic idea of OOCSS is to separate your CSS into reusable objects, which can be used anywhere you need on your site. The standard example of OOCSS is the pattern described as <a href="/en-US/docs/Web/CSS/Layout_cookbook/Media_objects">The Media Object</a>. This is a pattern with a fixed size image, video or other element on one side, and flexible content on the other. It's a pattern we see all over websites for comments, listings, and so on.</p> + +<p>If you are not taking an OOCSS approach you might create custom CSS for the different places this pattern is used, for example creating a class called <code>comment</code> with a bunch of rules for the component parts, then a class called <code>list-item</code> with almost the same rules as the <code>comment</code> class except for some tiny differences. The differences between these two components is that the list-item has a bottom border, and images in comments have a border whereas list-item images do not.</p> + +<pre class="brush: css">.comment { + display: grid; + grid-template-columns: 1fr 3fr; +} + +.comment img { + border: 1px solid grey; +} + +.comment .content { + font-size: .8rem; +} + +.list-item { + display: grid; + grid-template-columns: 1fr 3fr; + border-bottom: 1px solid grey; +} + +.list-item .content { + font-size: .8rem; +}</pre> + +<p>In OOCSS, you would create one pattern called <code>media</code> that would have all of the common CSS for both patterns — a base class for things that are generally the shape of the media object. Then we'd add an additional class to deal with those tiny differences, thus extending that styling in specific ways.</p> + +<pre class="brush: css">.media { + display: grid; + grid-template-columns: 1fr 3fr; +} + +.media .content { + font-size: .8rem; +} + +.comment img { + border: 1px solid grey; +} + + .list-item { + border-bottom: 1px solid grey; +} </pre> + +<p>In your HTML the comment would need both the <code>media</code> and <code>comment</code> classes applied:</p> + +<pre class="brush: html"><div class="media comment"> + <img /> + <div class="content"></div> +</div> +</pre> + +<p>The list-item would have <code>media</code> and <code>list-item</code> applied:</p> + +<pre class="brush: html"><ul> + <li class="media list-item"> + <img /> + <div class="content"></div> + </li> +</ul></pre> + +<p>The work that Nicole Sullivan did in describing this approach and promoting it means that even people who are not strictly following an OOCSS approach today will generally be reusing CSS in this way — it has entered our understanding as a good way to approach things in general.</p> + +<h4 id="BEM">BEM</h4> + +<p>BEM stands for Block Element Modifier. In BEM a block is a standalone entity such as a button, menu, or logo. An element is something like a list item or a title that is tied to the block it is in. A modifier is a flag on a block or element that changes the styling or behavior. You will be able to recognise code that uses BEM due to the extensive use of dashes and underscores in the CSS classes. For example, look at the classes applied to this HTML from the page about <a href="http://getbem.com/naming/">BEM Naming conventions</a>:</p> + +<pre class="brush: html"><form class="form form--theme-xmas form--simple"> + <input class="form__input" type="text" /> + <input + class="form__submit form__submit--disabled" + type="submit" /> +</form></pre> + +<p>The additional classes are similar to those used in the OOCSS example, however they use the strict naming conventions of BEM.</p> + +<p>BEM is widely used in larger web projects and many people write their CSS in this way. It is likely that you will come across examples, even in tutorials, that use BEM syntax, without mentioning why the CSS is structured in such a way.</p> + +<p>To read more about the system read <a href="https://css-tricks.com/bem-101/">BEM 101</a> on CSS Tricks.</p> + +<h4 id="Other_common_systems">Other common systems</h4> + +<p>There are a large number of these systems in use. Other popular approaches include <a href="http://smacss.com/">Scalable and Modular Architecture for CSS (SMACSS)</a>, created by Jonathan Snook, <a href="https://itcss.io/">ITCSS</a> from Harry Roberts, and <a href="https://acss.io/">Atomic CSS (ACSS)</a>, originally created by Yahoo!. If you come across a project that uses one of these approaches then the advantage is that you will be able to search and find many articles and guides to help you understand how to code in the same style.</p> + +<p>The disadvantage of using such a system is that they can seem overly complex, especially for smaller projects.</p> + +<h3 id="Build_systems_for_CSS">Build systems for CSS</h3> + +<p>Another way to organise CSS is to take advantage of some of the tooling that is available for front-end developers, which allows you to take a slightly more programmatic approach to writing CSS. There are a number of tools which we refer to as <em>pre-processors</em> and <em>post-processors</em>. A pre-processor runs over your raw files and turns them into a stylesheet, whereas a post-processor takes your finished stylesheet and does something to it — perhaps to optimize it in order that it will load faster.</p> + +<p>Using any of these tools will require that your development environment can run the scripts that do the pre and post-processing. Many code editors can do this for you, or you can install command line tools to help.</p> + +<p>The most popular pre-processor is <a href="https://sass-lang.com/">Sass</a>. This is not a Sass tutorial, so I will briefly explain a couple of the things that Sass can do, which are really helpful in terms of organisation, even if you don't use any of the other Sass features.</p> + +<h4 id="Defining_variables">Defining variables</h4> + +<p>CSS now has native <a href="/en-US/docs/Web/CSS/Using_CSS_custom_properties">custom properties</a>, making this feature increasingly less important, however one of the reasons you might use Sass is to be able to define all of the colors and fonts used in a project as settings, then use that variable around the project. This means that if you realise you have used the wrong shade of blue, you only need change it in one place.</p> + +<p>If we created a variable called <code>$base-color</code> as in the first line below, we could then use it through the stylesheet anywhere that required that color.</p> + +<pre class="brush: css"><code>$base-color: #c6538c; + +.alert { + border: 1px solid $base-color; +}</code></pre> + +<p>Once compiled to CSS, you would end up with the following CSS in the final stylesheet.</p> + +<pre class="brush: css"><code>.alert { + border: 1px solid #c6538c; +}</code></pre> + +<h4 id="Compiling_component_stylesheets">Compiling component stylesheets</h4> + +<p>I mentioned above that one way to organise CSS is to break down stylesheets into smaller stylesheets. When using Sass you can take this to another level and have lots of very small stylesheets — even going as far as having a separate stylesheet for each component. By using the include functionality in Sass these can then all be compiled together into one, or a small number of stylesheets to actually link into your website.</p> + +<p>You can see how one developer approaches the problem in <a href="https://www.lauraleeflores.com/blog/how-to-organize-your-css-files">this blog post</a>.</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: A simple way to try out Sass is to use <a href="https://codepen.io">CodePen</a> — you can enable Sass for your CSS in the Settings for a Pen, and CodePen will then run the Sass parser for you, in order that you can see the resulting webpage with regular CSS applied. Sometimes you will find that CSS tutorials have used Sass rather than plain CSS in their CodePen demos, so it is handy to know a little bit about it.</p> +</div> + +<h4 id="Post-processing_for_optimization">Post-processing for optimization</h4> + +<p>If you are concerned about adding size to your stylesheets by adding a lot of additional comments and whitespace for example, then a post-processing step could be to optimize the CSS by stripping out anything unneccessary in the production version. An example of a post-processor solution for doing this would be <a href="https://cssnano.co/">cssnano</a>.</p> + +<h2 id="Wrapping_up">Wrapping up</h2> + +<p>This is the final part of our Learning CSS Guide, and as you can see there are many ways in which your exploration of CSS can continue from this point.</p> + +<p>To learn more about layout in CSS, see the <a href="/en-US/docs/Learn/CSS/CSS_layout">Learn CSS Layout</a> section.</p> + +<p>You should also now have the skills to explore the rest of the <a href="/en-US/docs/Web/CSS">MDN CSS</a> material. You can look up properties and values, explore our <a href="/en-US/docs/Web/CSS/Layout_cookbook">CSS Cookbook</a> for patterns to use, and read more in some of the specific guides such as our <a href="/en-US/docs/Web/CSS/CSS_Grid_Layout">Guide to CSS Grid Layout</a>.</p> + +<p>{{PreviousMenu("Learn/CSS/Building_blocks/Debugging_CSS", "Learn/CSS/Building_blocks")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ol> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance">Cascade and inheritance</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors">CSS selectors</a> + <ul> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Type_Class_and_ID_Selectors">Type, class, and ID selectors</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Attribute_selectors">Attribute selectors</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Pseudo-classes_and_pseudo-elements">Pseudo-classes and pseudo-elements</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Combinators">Combinators</a></li> + </ul> + </li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/The_box_model">The box model</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Backgrounds_and_borders">Backgrounds and borders</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Handling_different_text_directions">Handling different text directions</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Overflowing_content">Overflowing content</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Values_and_units">Values and units</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Sizing_items_in_CSS">Sizing items in CSS</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Images_media_form_elements">Images, media, and form elements</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Styling_tables">Styling tables</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Debugging_CSS">Debugging CSS</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Organizing">Organizing your CSS</a></li> +</ol> diff --git a/files/ko/learn/css/building_blocks/overflowing_content/index.html b/files/ko/learn/css/building_blocks/overflowing_content/index.html new file mode 100644 index 0000000000..2cb71a8e6a --- /dev/null +++ b/files/ko/learn/css/building_blocks/overflowing_content/index.html @@ -0,0 +1,119 @@ +--- +title: 콘텐츠 overflow +slug: Learn/CSS/Building_blocks/Overflowing_content +translation_of: Learn/CSS/Building_blocks/Overflowing_content +--- +<div>{{LearnSidebar}}{{PreviousMenuNext("Learn/CSS/Building_blocks/Handling_different_text_directions", "Learn/CSS/Building_blocks/Values_and_units", "Learn/CSS/Building_blocks")}}</div> + +<p>이번 수업에서는 CSS 의 또 다른 중요한 개념인 — <strong>overflow</strong> 를 살펴봅니다. Overflow 는 박스 안에 편안하게 담기에는 너무 많은 내용이 있을 때 발생합니다. 이 안내서에서는 내용과 관리 방법에 대해 설명합니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">전제조건:</th> + <td>기본 컴퓨터 활용 능력, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Installing_basic_software">기본 소프트웨어 설치</a>, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Dealing_with_files">파일 작업</a> 에 대한 기본 지식, HTML 기본 사항 (<a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">HTML 소개</a> 학습) 및 , CSS 작동 방식 이해 (<a href="/en-US/docs/Learn/CSS/First_steps">CSS 첫 번째 단계</a> 학습)</td> + </tr> + <tr> + <th scope="row">목적:</th> + <td>overflow 및 이를 관리하는 방법 이해하기.</td> + </tr> + </tbody> +</table> + +<h2 id="overflow_란_무엇인가">overflow 란 무엇인가?</h2> + +<p>우리는 이미 CSS 의 모든 것이 박스라는 것을 알고 있으며, {{cssxref("width")}} 및 {{cssxref("height")}} (또는 {{cssxref("inline-size")}} 및 {{cssxref("block-size")}}) 의 값을 제공하여 박스의 크기를 제한할 수 있음을 알고 있습니다. Overflow 는 박스에 내용이 너무 많을 때 발생하므로, 박스 안에 들어가지 않습니다. CSS 는 이 overflow 를 관리할 수 있는 다양한 도구를 제공하며, 이 초기 단계에서 이해하는 데 유용한 개념이기도 합니다. CSS 를 작성할 때, 특히 CSS 레이아웃에 더 깊이 들어가면 overflow 상황이 자주 발생합니다.</p> + +<h2 id="CSS_는_데이터_손실_을_피하려고_합니다">CSS 는 "데이터 손실" 을 피하려고 합니다</h2> + +<p>overflow 가 발생했을 때, CSS 가 기본적으로 어떻게 동작하는지 보여주는 두 가지 예를 살펴보도록 하겠습니다.</p> + +<p>찻 번째는 <code>height</code> 를 지정하여 블록 크기가 제한된 박스입니다. 그런 다음 이 박스에 필요한 공간보다 많은 콘텐츠를 추가했습니다. 내용물이 박스에 넘쳐서 박스 아래의 단락 위에 다소 혼란스럽게 놓여 있습니다.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/overflow/block-overflow.html", '100%', 600)}}</p> + +<p>두 번째는 인라인 크기로 제한된 박스의 단어입니다. 박스가 해당 단어에 맞지 않도록 너무 작게 만들어져 박스 밖으로 나옵니다.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/overflow/inline-overflow.html", '100%', 500)}}</p> + +<p>왜 CSS 가 기본적으로 내용이 혼란스러워지는 어수선한 접근 방식을 취했는지 궁금할 것입니다. 추가 콘텐츠를 숨기거나 박스가 커지는 이유는 무엇입니까?</p> + +<p>가능하면 CSS 는 내용을 숨기지 않습니다; 그렇게 하면 데이터가 손실될 수 있으며, 이는 일반적으로 문제입니다. CSS 용어로, 이는 일부 콘텐츠가 사라짐을 의미합니다. 콘텐츠 손실의 문제점은 손실 되었음을 알 수 없다는 것입니다. 방문자가 사라진 것을 눈치채지 못할 수도 있습니다. 그것이 사라지는 양식의 제출 버튼이고 아무도 양식을 완성할 수 없다면 큰 문제입니다! 따라서 CSS 는 눈에 띄게 overflow 되는 경향이 있습니다. 혼란스러워 보이거나, 최악의 경우 사이트 방문자가 일부 콘텐츠가 겹치므로 수정해야함을 알려줍니다.</p> + +<p><code>width</code> 또는<code>height</code> 가 있는 박스를 제한한 경우, CSS 는 사용자가 수행중인 작업을 알고 있으며, overflow 가능성을 관리한다고 가정합니다. 일반적으로 사이트를 디자인할 때 예상보다 많은 텍스트가 있거나 텍스트가 더 클 수 있으므로 — 예를 들어 사용자가 글꼴 크기를 늘린 경우 박스에 텍스트를 넣을 때 블록 크기를 제한하는 것은 문제가 됩니다.</p> + +<p>다음 수업에서는 overflow 가 덜 발생하는 크기를 제어하는 다양한 방법을 살펴보겠습니다. 그러나 고정 크기가 필요한 경우, overflow 동작을 제어할 수도 있습니다. 계속 읽어 봅시다!</p> + +<h2 id="overflow_속성">overflow 속성</h2> + +<p>{{cssxref("overflow")}} 속성은 요소의 overflow 를 제어하고 브라우저가 원하는 방식으로 동작하도록 하는 방법입니다. overflow 의 기본값은 <code>visible</code> 이므로, overflows 가 발생하면 기본적으로 콘텐츠를 볼 수 있습니다.</p> + +<p>콘텐츠가 넘칠 때 내용을 자르려면 박스에 <code>overflow: hidden</code> 을 설정할 수 있습니다. 이렇게 하면 — overflow 를 숨길 수 있습니다. 이로 인해 모든 것이 사라질 수 있으므로 콘텐츠를 숨기는 것이 문제를 일으키지 않을 경우에만 해야합니다.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/overflow/hidden.html", '100%', 600)}}</p> + +<p>아마도 내용이 넘칠 때 스크롤 막대를 추가하고 싶습니까? <code>overflow: scroll</code> 를 사용하면 브라우저에 항상 스크롤 막대가 표시됩니다 — 콘텐츠가 부족하여 overflow 할 수 없는 경우에도 마찬가지입니다. 내용에 따라 스크롤 막대가 나타나거나 사라지는 것을 방지하기 때문에 원하는 경우가 있습니다.</p> + +<p><strong>아래 박스에서 일부 내용을 제거하면 스크롤 할 내용이 없어도 스크롤 막대가 여전히 남아 있습니다 (또는 스크롤 막대만).</strong></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/overflow/scroll.html", '100%', 600)}}</p> + +<p>위의 예제에서는 <code>y</code> 축만 스크롤하면 되지만, 두 축에는 스크롤바가 나타납니다. 대신 {{cssxref("overflow-y")}} 속성을 사용하여, <code>overflow-y: scroll</code> 로 설정하면 <code>y</code> 축에서만 스크롤하도록 할 수 있습니다.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/overflow/scroll-y.html", '100%', 600)}}</p> + +<p>{{cssxref("overflow-x")}} 를 사용하여 x 축을 스크롤할 수도 있지만, 긴 단어를 처리하는 데 권장되는 방법은 아닙니다! 작은 박스에서 긴 단어를 처리해야 하는 경우 {{cssxref("word-break")}} 또는 {{cssxref("overflow-wrap")}} 속성을 볼 수 있습니다. 또한 <a href="/en-US/docs/Learn/CSS/Building_blocks/Sizing_items_in_CSS">CSS 항목 크기 조정</a> 에서 설명하는 일부 방법을 사용하면 다양한 양의 콘텐츠에 더 잘 맞는 박스를 만들 수 있습니다.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/overflow/scroll-x.html", '100%', 500)}}</p> + +<p><code>scroll</code> 과 마찬가지로 스크롤 막대를 유발할 내용이 충분한 지 여부에 따라 스크롤 크기에 스크롤 막대가 나타납니다.</p> + +<div class="blockIndicator note"> +<p><strong>참고</strong>: <code>overflow</code> 속성을 사용하여 두 개의 값을 전달하여 x 와 y 스크롤을 지정할 수 있습니다. 두 개의 키워드가 지정되면, 첫 번째 키워드는 <code>overflow-x</code> 에 적용되고 두 번째 키워드는 <code>overflow-y</code> 에 적용됩니다. 그렇지 않으면 <code>overflow-x</code> 및 <code>overflow-y</code> 가 모두 같은 값으로 설정됩니다. 예를 들어, <code>overflow: scroll hidden</code> 은 <code>overflow-x</code> 를 <code>scroll</code> 로, <code>overflow-y</code> 를 <code>hidden</code> 으로 설정합니다.</p> +</div> + +<p>박스에 넣을 수 있는 것보다 많은 내용이 있는 경우 스크롤 막대만 표시하려면, <code>overflow: auto</code> 를 사용하십시오. 이 경우 스크롤 막대를 표시할 지 여부를 결정하는 것은 브라우저에게 맡겨져 있습니다. 데스크톱 브라우저는 일반적으로 overflow 를 유발할 수 있는 충분한 콘텐츠가 있는 경우에만 그렇게 합니다.</p> + +<p><strong>아래 예에서 박스에 들어갈 때까지 일부 내용을 제거하면, 스크롤 막대가 사라지는것을 볼 수 있습니다.</strong></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/overflow/auto.html", '100%', 600)}}</p> + +<h2 id="Overflow_는_블록_서식_Context_를_설정합니다">Overflow 는 블록 서식 Context 를 설정합니다</h2> + +<p>CSS 에는 <strong>Block Formatting Context</strong> (BFC) 의 개념이 있습니다. 이것은 지금 너무 걱정할 필요는 없지만, <code>scroll</code> 또는 <code>auto</code> 와 같은 overflow 값을 사용할 때 BFC 를 생성한다는 것을 아는 것이 유용합니다. 결과적으로 <code>overflow</code> 값을 변경한 박스의 내용이 자체의 미니 레이아웃이 됩니다. container 외부의 물건은 container 에 찌를 수 없으며, 박스에서 주변 레이아웃으로 찌를 수는 없습니다. 이느 일관된 스크롤 환경을 만들기 위해, 박스의 모든 내용을 포함해야 하고 페이지의 다른 항목과 겹치지 않아야 하므로 스크롤 동작을 활성화하기 위한 것입니다.</p> + +<h2 id="웹_디자인에서_원치_않는_overflow">웹 디자인에서 원치 않는 overflow</h2> + +<p>최신 레이아웃 방법 (<a href="/en-US/docs/Learn/CSS/CSS_layout">CSS 레이아웃</a> 강의에 설명되어 있음) 은 overflow 를 매우 잘 관리합니다. 우리가 웹에 얼마나 많은 콘텐츠를 가지고 있는지 예측할 수 없다는 사실에 대처하도록 설계되었습니다. 그러나 과거에는 개발자들이 종종 고정된 높이를 사용하여 서로 관계가 없는 박스의 하단을 정렬하려고 했습니다. 이것은 깨지기 쉬웠으며, legacy 응용 프로그램에서 때때로 내용이 페이지의 다른 내용과 겹치는 박스가 나타날 수 있습니다. 이러한 현상이 나타나면 overflow 가 발생한다는 것을 알수 있습니다. 박스 크기 고정에 의존하지 않도록 레이아웃을 리팩터링 하는것이 이상적입니다.</p> + +<p>사이트를 개발할 때는 항상 overflow 문제를 염두에 두어야 합니다. 많은 양의 콘텐츠로 디자인을 테스트하고 텍스트의 글꼴 크기를 늘리면 CSS 가 강력한 방식으로 대처할 수 있는지 확인해야 합니다. 내용을 숨기거나 스크롤 막대를 추가하기 위해 overflow 값을 변경하는 것은 스크롤 박스를 원할 때와 같은 몇 가지 특별한 경우에만 예약할 수 있습니다.</p> + +<h2 id="요약">요약</h2> + +<p>이 짧은 수업은 overflow 개념을 소개했습니다; 이제 CSS 가 넘쳐나는 내용을 보이지 않게 만들려고 하지만 데이터가 손실될 수 있음을 이해합니다. overflow 가능성을 관리할 수 있으며 실수로 overflow 문제가 발생하지 않도록 작업을 테스트해야 합니다.</p> + +<p>{{PreviousMenuNext("Learn/CSS/Building_blocks/Handling_different_text_directions", "Learn/CSS/Building_blocks/Values_and_units", "Learn/CSS/Building_blocks")}}</p> + +<h2 id="이번_강의에서는">이번 강의에서는</h2> + +<ol> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance">계단식 및 상속</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors">CSS 선택자</a> + <ul> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Type_Class_and_ID_Selectors">Type, class 및 ID 선택자</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Attribute_selectors">속성 선택자</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Pseudo-classes_and_pseudo-elements">Pseudo-classes 및 pseudo-elements</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Combinators">결합자</a></li> + </ul> + </li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/The_box_model">박스 모델</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Backgrounds_and_borders">배경 및 테두리</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Handling_different_text_directions">다른 텍스트 방향 처리</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Overflowing_content">콘텐츠 overflow</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Values_and_units">값 과 단위</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Sizing_items_in_CSS">CSS 에서 항목 크기 조정</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Images_media_form_elements">이미지, 미디어 및 양식 요소</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Styling_tables">표 스타일링</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Debugging_CSS">CSS 디버깅</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Organizing">CSS 정리</a></li> +</ol> diff --git a/files/ko/learn/css/building_blocks/sizing_items_in_css/index.html b/files/ko/learn/css/building_blocks/sizing_items_in_css/index.html new file mode 100644 index 0000000000..321d65d726 --- /dev/null +++ b/files/ko/learn/css/building_blocks/sizing_items_in_css/index.html @@ -0,0 +1,131 @@ +--- +title: CSS 에서 항목 크기 조정 +slug: Learn/CSS/Building_blocks/Sizing_items_in_CSS +translation_of: Learn/CSS/Building_blocks/Sizing_items_in_CSS +--- +<div>{{LearnSidebar}}{{PreviousMenuNext("Learn/CSS/Building_blocks/Values_and_units", "Learn/CSS/Building_blocks/Images_media_form_elements", "Learn/CSS/Building_blocks")}}</div> + +<p>지금까지 다양한 수업에서는 CSS 를 사용하여 웹 페이지의 항목 크기를 조정하는 여러가지 방법을 살펴 보았습니다. 디자인의 다양한 기능이 얼마나 큰지 이해하는 것이 중요하며, 이 수업에서는 CSS 를 통해 요소의 크기를 결정하는 다양한 방법을 요약하고 크기 조정과 관련하여 향후 도움이 될 몇 가지 용어를 정의합니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">전제조건:</th> + <td> + <p>기본 컴퓨터 활용 능력, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Installing_basic_software">기본 소프트웨어 설치</a>, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Dealing_with_files">파일 작업</a> 에 대한 기본 지식, HTML 기본 사항 (<a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">HTML 소개</a> 학습) 및 , CSS 작동 방식 이해 (<a href="/en-US/docs/Learn/CSS/First_steps">CSS 첫 번째 단계</a> 학습)</p> + </td> + </tr> + <tr> + <th scope="row">목적:</th> + <td>CSS 로 크기를 조정할 수 있는 다양한 방법 이해하기.</td> + </tr> + </tbody> +</table> + +<h2 id="사물의_자연적_또는_본질적인_크기">사물의 자연적 또는 본질적인 크기</h2> + +<p>HTML 요소는 CSS 의 영향을 받기 전에 설정한 자연스러운 크기입니다. 간단한 예는 이미지입니다. 이미지는 페이지에 포함된 이미지 파일에 정의된 너비와 높이를 갖습니다. 이 크기는 이미지 자체에서 나오는 — <strong>고유 크기 (intrinsic size)</strong> 로 설명됩니다.</p> + +<p>페이지에 이미지를 배치하고 <code><img></code> 태그 또는 CSS 의 속성을 사용하여 높이와 너비를 변경하지 않으면, 고유 크기를 사용하여 이미지가 표시됩니다. 파일의 범위를 볼 수 있도록 아래 예제의 이미지에 테두리를 지정했습니다.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/sizing/intrinsic-image.html", '100%', 600)}}</p> + +<p>그러나 빈 {{htmlelement("div")}} 에는, 자체 크기가 없습니다. 내용이 없는 HTML 에 {{htmlelement("div")}} 를 추가한 다음 이미지와 마찬가지로 테두리를 지정하면, 페이지에 한 라인이 표시됩니다. 이것은 요소의 접힌 (collapsed) 테두리입니다 — 열려야 할 내용이 없습니다. 아래 예제에서, 이 테두리는 container 의 너비까지 확장됩니다. 이는 블록 레벨 요소이기 때문에 친숙해지기 시작해야 합니다. 내용이 없기 때문에 높이 (또는 블록의 크기) 가 없습니다.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/sizing/intrinsic-text.html", '100%', 500)}}</p> + +<p>위의 예에서, 빈 요소 안에 텍스트를 추가하십시오. 요소의 높이가 내용에 의해 정의되므로 테두리에 해당 텍스트가 포함됩니다. 따라서 블록 차원에서 이 <code><div></code> 의 크기는 내용의 크기에서 비롯됩니다. 다시 말하지만, 이것은 요소의 고유 크기입니다 — 크기는 내용에 의해 정의됩니다.</p> + +<h2 id="특정_크기_설정">특정 크기 설정</h2> + +<p>물론 디자인의 요소에 특정 크기를 줄 수 있습니다. 요소에 크기가 주어지면 (그리고 그 내용이 그 크기에 맞아야 함) 우리는 이것을 <strong>외적인 크기 (extrinsic size)</strong> 로 지칭합니다. 위의 예에서 <code><div></code> 를 가져와서 — 구체적인 {{cssxref("width")}} 및 {{cssxref("height")}} 값을 지정할 수 있으며, 이제 어떤 내용이 들어가든 해당 크기를 갖습니다. <a href="/en-US/docs/Learn/CSS/Building_blocks/Overflowing_content">overflow 에 대한 이전 수업</a> 에서 발견한 것처럼 요소에 맞는 공간보다 많은 콘텐츠가 있으면 설정된 높이로 인해 콘텐츠가 overflow 될 수 있습니다.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/sizing/height.html", '100%', 600)}}</p> + +<p>이 overflow 문제로 인해, 요소의 높이를 길이 또는 백분율로 고정하는 것은 웹에서 매우 신중하게 수행해야 하는 작업입니다.</p> + +<h3 id="백분율_사용하기">백분율 사용하기</h3> + +<p>여러 방법으로 백분율은 길이 단위처럼 작동하며, <a href="/en-US/docs/Learn/CSS/Building_blocks/Values_and_units#Percentages">값과 단위에 대한 수업에서 논의한 것처럼</a>, 종종 길이와 상호 교환적으로 사용될 수 있습니다. 백분율을 사용하는 경우 백분율이 <strong><em>얼마인지</em></strong> 알고 있어야 합니다. 다른 container 안에 있는 박스의 경우 자식 박스에 백분율 너비를 지정하면, 부모 container 너비의 백분율이 됩니다.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/sizing/percent-width.html", '100%', 600)}}</p> + +<p>백분율을 포함하는 블록의 크기에 대해 결정되기 때문입니다. 백분율이 적용되지 않으면 <code><div></code> 는 블록 레벨 요소이므로 사용가능한 공간의 100% 를 차지합니다. 너비를 백분율로 지정하면, 일반적으로 채워지는 공간의 백분율이 됩니다.</p> + +<h3 id="백분율_마진_및_패딩">백분율 마진 및 패딩</h3> + +<p><code>margins</code> 과 <code>padding</code> 을 백분율로 설정하면 이상한 동작이 나타날 수 있습니다. 아래 예제에는 박스가 있습니다. 내부 박스에 {{cssxref("margin")}} 을 10% 로, {{cssxref("padding")}} 을 10% 로 지정했습니다. 박스 상단과 하단의 패딩과 마진은 왼쪽과 오른쪽의 마진과 크기가 같습니다.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/sizing/percent-mp.html", '100%', 700)}}</p> + +<p>예를 들어 상단 및 하단 마진 백분율이 요소 높이의 백분율이고, 왼쪽 및 오른쪽 마진 백분율이 요소 너비의 백분율일 것으로 예상할 수 있습니다. 그러나, 이것은 사실이 아닙니다!</p> + +<p>백분율로 마진 및 패딩을 사용하는 경우, 값은 <strong>인라인 크기 (inline size) </strong>에서 계산되므로 — horizontal 언어로 작업할 때의 너비입니다. 이 예에서 모든 마진과 패딩은 너비의 10% 입니다. 즉, 박스 전체에 같은 크기의 마진과 패딩을 둘 수 있습니다. 이 방법으로 백분율을 사용하면 기억할 가치가 있습니다.</p> + +<h2 id="min-_및_max-_크기">min- 및 max- 크기</h2> + +<p>고정된 크기를 주는 것 외에도, CSS 에 요소에 최소 또는 최대 크기를 제공하도록 요청할 수 있습니다. 가변적인 양의 내용을 포함할 수 있는 박스가 있고, <strong><em>항상</em></strong> 특정 높이 이상이 되도록 하려면, {{cssxref("min-height")}} 속성을 설정할 수 있습니다. 박스는 항상 이 높이 이상이지만, 박스의 최소 높이에 대한 공간보다 더 많은 내용이 있으면 키가 더 커집니다.</p> + +<p>아래 예에서 정의된 높이가 150 픽셀인 두 개의 박스를 볼 수 있습니다. 왼쪽의 박스는 키가 150 픽셀입니다; 오른쪽의 상자에는 더 많은 공간이 필요한 내용이 있으므로, 최소 150 픽셀 이상으로 키가 커졌습니다.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/sizing/min-height.html", '100%', 800)}}</p> + +<p>이는 overflow 를 피하면서 가변적인 양의 콘텐츠를 처리할 때 매우 유용합니다.</p> + +<p>{{cssxref("max-width")}} 의 일반적인 용도는 이미지를 원래 너비로 표시할 공간이 충분하지 않으면 이미지의 크기를 줄이면서, 해당 너비보다 크게되지 않도록 하는것입니다.</p> + +<p>예를 들어, 이미지에서 <code>width: 100%</code> 를 설정하고 이미지의 고유 (intrinsic) 너비가 container 보다 작으면, 이미지가 강제로 늘어나고 커져 픽셀화되어 나타납니다. 고유 너비가 container 보다 크면 overflow 됩니다. 두 경우 모두 여러분이 원하는 것이 아닙니다.</p> + +<p><code>max-width: 100%</code> 를 대신 사용하면, 이미지가 고유 크기보다 작아질 수 있지만, 크기의 100% 에서 멈춥니다.</p> + +<p>아래 예에서는 동일한 이미지를 두 번 사용했습니다. 첫 번째 이미지에는 <code>width: 100%</code> 로 주어졌으며, 그보다 큰 container 에 있으므로 container 너비로 늘어납니다. 두 번째 이미지에는 <code>max-width: 100%</code> 로 설정되어 있으므로 container 를 채우기 위해 늘어나지 않습니다. 세 번째 박스에는 동일한 이미지가 다시 포함되며, <code>max-width: 100%</code> 로 설정됩니다; 이 경우 박스에 맞게 크기가 어떻게 축소되었는지 확인할 수 있습니다.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/sizing/max-width.html", '100%', 800)}}</p> + +<p>이 기술은 이미지를 반응형으로 만드는 데 사용되므로 더 작은 장치에서 볼 때 이미지가 적절하게 축소됩니다. 그러나 이 기술을 사용하여 실제로 큰 이미지를 로드한 다음 브라우저에서 축소하면 안됩니다. 이미지는 디자인에 표시되는 가장 큰 크기보다 커야합니다. 지나치게 큰 이미지를 다운로드하면, 사이트 속도가 느려질 수 있으며, 데이터 요금제인 경우 더 많은 비용이 발생할 수 있습니다.</p> + +<div class="blockIndicator note"> +<p><strong>참고</strong>: <a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images">반응형 이미지 기술</a> 에 대해 자세히 알아보십시오.</p> +</div> + +<h2 id="Viewport_단위">Viewport 단위</h2> + +<p>Viewport — 사이트를 보는 데 사용하는 브라우저에서 페이지의 가시 영역 — 또한 크기가 있습니다. CSS 에는 viewport 의 크기와 관련된 단위가 있습니다 — viewport 너비의 경우 <code>vw</code> 단위, viewport 높이의 경우 <code>vh</code>. 이 단위를 사용하면 사용자의 viewport 에 상대적인 크기를 지정할 수 있습니다.</p> + +<p><code>1vh</code> 는 viewport 높이의 1% 와 같고, <code>1vw</code> 는 viewport 너비의 1% 와 같습니다. 이 단위를 사용하여 박스 크기 뿐만 아니라, 텍스트도 조정할 수 있습니다. 아래 예에서는 20vh 및 20vw 크기의 박스가 있습니다. 박스에는 문자 <code>A</code> 가 포함되어 있으며 {{cssxref("font-size")}} 에 10vh 가 지정되었습니다.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/sizing/vw-vh.html", '100%', 600)}}</p> + +<p><strong> <code>vh</code> 및 <code>vw</code> 값을 변경하면 박스 또는 글꼴의 크기가 변경됩니다; viewport 크기를 변경하면 viewport 를 기준으로 크기가 조정되므로 크기도 변경됩니다. viewport 크기를 변경할 때 예제 변경 사항을 보려면 크기를 조정할 수 있는 새 브라우저 창에 예제를 로드해야 합니다 (위에 표시된 예제가 포함된 <code><iframe></code> 이 viewport 임). <a href="https://mdn.github.io/css-examples/learn/sizing/vw-vh.html">예제를 열고</a>, 브라우저 창의 크기를 조정한 후 박스와 텍스트의 크기에 어떤 영향이 있는지 관찰하십시오.</strong></p> + +<p>viewport 에 따라 크기를 조정하면 디자인에 유용할 수 있습니다. 예를 들어, 전체 콘텐츠 페이지 섹셩을 콘텐츠의 나머지 부분보다 먼저 표시하려면, 페이지의 해당 부분을 100vh 높이로 설정하면 나머지 콘텐츠가 viewport 아래로 밀려서 문서가 스크롤 된 후에만 표시됩니다.</p> + +<h2 id="요약">요약</h2> + +<p>이번 수업에서는 웹에서 크기를 조정할 때 발생할 수 있는 몇 가지 주요 문제에 대해 설명합니다. <a href="/en-US/docs/Learn/CSS/CSS_layout">CSS 레이아웃</a> 으로 이동할 때, 크기 조정은 다양한 레이아웃 방법을 익히는 데 매우 중요하므로 계속 진행하기 전에 여기에서 개념을 이해하는 것이 좋습니다.</p> + +<p>{{PreviousMenuNext("Learn/CSS/Building_blocks/Values_and_units", "Learn/CSS/Building_blocks/Images_media_form_elements", "Learn/CSS/Building_blocks")}}</p> + +<h2 id="이번_강의에서는">이번 강의에서는</h2> + +<ol> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance">계단식 및 상속</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors">CSS 선택자</a> + <ul> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Type_Class_and_ID_Selectors">Type, class 및 ID 선택자</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Attribute_selectors">속성 선택자</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Pseudo-classes_and_pseudo-elements">Pseudo-classes 및 pseudo-elements</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Combinators">결합자</a></li> + </ul> + </li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/The_box_model">박스 모델</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Backgrounds_and_borders">배경 및 테두리</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Handling_different_text_directions">다른 텍스트 방향 처리</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Overflowing_content">콘텐츠 overflow</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Values_and_units">값 과 단위</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Sizing_items_in_CSS">CSS 에서 항목 크기 조정</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Images_media_form_elements">이미지, 미디어 및 양식 요소</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Styling_tables">표 스타일링</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Debugging_CSS">CSS 디버깅</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Organizing">CSS 정리</a></li> +</ol> diff --git a/files/ko/learn/css/building_blocks/styling_tables/index.html b/files/ko/learn/css/building_blocks/styling_tables/index.html new file mode 100644 index 0000000000..fb497ebfe2 --- /dev/null +++ b/files/ko/learn/css/building_blocks/styling_tables/index.html @@ -0,0 +1,308 @@ +--- +title: 표 스타일링 +slug: Learn/CSS/Building_blocks/Styling_tables +translation_of: Learn/CSS/Building_blocks/Styling_tables +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/CSS/Building_blocks/Images_media_form_elements", "Learn/CSS/Building_blocks/Debugging_CSS", "Learn/CSS/Building_blocks")}}</div> + +<p class="summary"></p> + +<p class="summary">HTML 표 스타일링은 세계에서 가장 매력적인 일이 아니지만, 때로는 우리 모두가 해야할 일입니다. 이 기사에서는 특정 표 스타일링 기술을 강조 표시하여 HTML 표를 보기좋게 만드는 방법에 대한 안내서를 제공합니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">전제조건:</th> + <td>HTML 기본 사항 (<a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">HTML 소개</a> 학습), <a href="/en-US/docs/Learn/HTML/Tables">HTML 표</a> 에 대한 지식 및 CSS 작동 방식에 대한 이해 (CSS 첫 번째 단계 학습.)</td> + </tr> + <tr> + <th scope="row">목적:</th> + <td>HTML 표를 효과적으로 스타일링하는 방법 배우기.</td> + </tr> + </tbody> +</table> + +<h2 id="전형적인_HTML_표">전형적인 HTML 표</h2> + +<p>전형적인 HTML 표를 살펴 봅시다. 글쎄요, 일반적인 표의 예들은 — 신발, 날씨 또는 직원들에 관한 것입니다; 우리는 영국의 유명한 펑크 밴드에 관한것을 만들어서 더 흥미롭게 만들기로 결정했습니다. 코드는 다음과 같습니다:</p> + +<pre class="brush: html"><table> + <caption>A summary of the UK's most famous punk bands</caption> + <thead> + <tr> + <th scope="col">Band</th> + <th scope="col">Year formed</th> + <th scope="col">No. of Albums</th> + <th scope="col">Most famous song</th> + </tr> + </thead> + <tbody> + <tr> + <th scope="row">Buzzcocks</th> + <td>1976</td> + <td>9</td> + <td>Ever fallen in love (with someone you shouldn't've)</td> + </tr> + <tr> + <th scope="row">The Clash</th> + <td>1976</td> + <td>6</td> + <td>London Calling</td> + </tr> + + ... some rows removed for brevity + + <tr> + <th scope="row">The Stranglers</th> + <td>1974</td> + <td>17</td> + <td>No More Heroes</td> + </tr> + </tbody> + <tfoot> + <tr> + <th scope="row" colspan="2">Total albums</th> + <td colspan="2">77</td> + </tr> + </tfoot> +</table></pre> + +<p>{{htmlattrxref("scope","th")}}, {{htmlelement("caption")}}, {{htmlelement("thead")}}, {{htmlelement("tbody")}} 등의 기능 덕분에 표가 잘 표시되고 쉽게 스타일링되며 액세스할 수 있습니다. 불행히도 화면에 렌더링할 때는 좋지 않습니다 (<a href="http://mdn.github.io/learning-area/css/styling-boxes/styling-tables/punk-bands-unstyled.html">punk-bands-unstyled.html</a> 에서 라이브 참조):</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13064/table-unstyled.png" style="display: block; margin: 0 auto;"></p> + +<p>기본 브라우저 스타일만 사용하면, 비좁고 읽기 어려우며 지루해 보입니다. 이 문제를 해결하려면 CSS 를 사용해야 합니다.</p> + +<h2 id="우리의_표_스타일링">우리의 표 스타일링</h2> + +<p>표 예제를 함께 스타일링 해 봅시다.</p> + +<ol> + <li>시작하려면, <a href="https://github.com/mdn/learning-area/blob/master/css/styling-boxes/styling-tables/punk-bands-unstyled.html">sample markup</a> 의 로컬 사본을 만들고 두 이미지 (<a href="https://github.com/mdn/learning-area/blob/master/css/styling-boxes/styling-tables/noise.png">노이즈</a> 및 <a href="https://github.com/mdn/learning-area/blob/master/css/styling-boxes/styling-tables/leopardskin.jpg">표범가죽</a>) 를 모두 다운로드한 다음, 세 개의 결과 파일을 로컬 컴퓨터의 작업 디렉토리에 넣습니다.</li> + <li>다음으로, <code>style.css</code> 라는 새 파일을 만들고 다른 파일과 같은 디렉토리에 저장하십시오.</li> + <li>{{htmlelement("head")}} 안에 다음 HTML 행을 배치하여 CSS 를 HTML 에 연결하십시오: + <pre class="brush: html"><link href="style.css" rel="stylesheet" type="text/css"></pre> + </li> +</ol> + +<h3 id="간격_및_레이아웃">간격 및 레이아웃</h3> + +<p>가장 먼저 해야할 일은 간격/레이아웃을 정렬하는 것입니다 — 기본 표 스타일은 너무 비좁습니다! 이렇게 하려면, <code>style.css</code> 파일에 다음 CSS 를 추가하십시오:</p> + +<pre class="brush: css">/* 간격 */ + +table { + table-layout: fixed; + width: 100%; + border-collapse: collapse; + border: 3px solid purple; +} + +thead th:nth-child(1) { + width: 30%; +} + +thead th:nth-child(2) { + width: 20%; +} + +thead th:nth-child(3) { + width: 15%; +} + +thead th:nth-child(4) { + width: 35%; +} + +th, td { + padding: 20px; +}</pre> + +<p>가장 중요한 부분은 다음과 같습니다:</p> + +<ul> + <li><code>fixed</code> 의 {{cssxref("table-layout")}} 값은 일반적으로 표가 기본적으로 좀 더 예측 가능하게 작동하므로 표에 설정하는 것이 좋습니다. 일반적으로, 표의 열은 내용의 양에 따라 크기가 정해지는 경향이 있으며, 그 결과 이상한 결과가 발생합니다. <code>table-layout: fixed</code> 를 사용하면 제목의 너비에 따라 열의 크기를 지정한 다음 내용을 적절하게 처리할 수 있습니다. 이것이 우리가 <code>thead th:nth-child(<em>n</em>)</code> ({{cssxref(":nth-child")}}) 선택자 ("{{htmlelement("thead")}} 요소 내에서 {{htmlelement("th")}} 요소인 <em>n번째</em> 자식 요소{{htmlelement("thead")}} 를 순서대로 선택합니다") 요소를 설정하고 백분율 너비를 설정했습니다. 전체 열 너비는 제목 너비를 따르므로, 표 열의 크기를 정할 수 있습니다. Chris Coyier 는 이 기술에 대해 <a href="https://css-tricks.com/fixing-tables-long-strings/">고정 표 레이아웃</a> 에서 자세히 설명합니다.<br> + <br> + 이를 {{cssxref("width")}} 와 100% 결합했습니다. 즉, 표에 넣은 container 를 표에 채우고 반응성이 뛰어납니다 (아직 더 많은 작업이 필요하지만 좁은 화면 너비에서 잘 보임).</li> + <li><code>collapse</code> 의 {{cssxref("border-collapse")}} 값은 모든 표 스타일 작업에 대한 표준 모범 사례입니다. 기본적으로, 표 요소에 테두리를 설정하면, 아래 이미지와 같이 테두리 사이에 간격이 있습니다: <img alt="" src="https://mdn.mozillademos.org/files/13068/no-border-collapse.png" style="display: block; margin: 0 auto;">이것은 매우 멋지게 보이지 않습니다 (원하는 모양일 수 있는지, 누가 알겠습니까?) <code>border-collapse: collapse;</code> 로 설정하면 테두리가 하나로 축소되어 훨씬 좋아 보입니다: <img alt="" src="https://mdn.mozillademos.org/files/13066/border-collapse.png" style="display: block; margin: 0 auto;"></li> + <li>우리는 전체 표 주위에 {{cssxref("border")}} 를 넣었습니다. 나중에 표 머리글과 바닥글에 테두리를 씌울 것입니다 — 표 바깥쪽에 테두리가 없고 틈새가 생기면 정말 이상하게 보입니다.</li> + <li>{{htmlelement("th")}} 및 {{htmlelement("td")}} 요소에 {{cssxref("padding")}} 을 설정했습니다 — 이렇게 하면 데이터 항목에 숨을 공간이 생깁니다. 표를 훨씬 읽기 쉽게 보이게합니다.</li> +</ul> + +<p>이 시점에서, 우리 표는 이미 훨씬 좋아보입니다:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13070/table-with-spacing.png" style="display: block; margin: 0 auto;"></p> + +<h3 id="간단한_typography">간단한 typography</h3> + +<p>이제 텍스트를 약간 정리해 보겠습니다.</p> + +<p>우선, <a href="https://www.google.com/fonts">Google Fonts</a> 에서 펑크 밴드 관련 표에 적합한 글꼴을 찾았습니다. 원하는 경우 거기에 가서 다른 것을 찾을 수 있습니다. 제공된 {{htmlelement("link")}} 요소 및 custom {{cssxref("font-family")}} 선언을 Google Fonts 에서 제공하는 선언으로 바꾸면 됩니다.</p> + +<p>먼저, 다음 {{htmlelement("link")}} 요소를 기존 <code><link></code> 요소 바로 위의 HTML head 에 추가하십시오:</p> + +<pre class="brush: html"><link href='https://fonts.googleapis.com/css?family=Rock+Salt' rel='stylesheet' type='text/css'></pre> + +<p>이제 이전 CSS 아래의 <code>style.css</code> 파일에, 다음 CSS 를 추가하십시오:</p> + +<pre class="brush: css">/* typography */ + +html { + font-family: 'helvetica neue', helvetica, arial, sans-serif; +} + +thead th, tfoot th { + font-family: 'Rock Salt', cursive; +} + +th { + letter-spacing: 2px; +} + +td { + letter-spacing: 1px; +} + +tbody td { + text-align: center; +} + +tfoot th { + text-align: right; +}</pre> + +<p>여기에서는 표에 특별한 것은 없습니다. 우리는 일반적으로 쉽게 읽을 수 있도록 글꼴 스타일을 조정합니다:</p> + +<ul> + <li>전역 sans-serif 글꼴 스택을 설정했습니다; 이것은 순전히 문체 선택입니다. 또한 {{htmlelement("thead")}} 및 {{htmlelement("tfoot")}} 요소의 제목에 맞춤 글꼴을 설정하여 멋지고 펑키한 모양을 만들었습니다.</li> + <li>가독성을 높이기 위해 제목과 셀에 {{cssxref("letter-spacing")}} 을 설정했습니다. 다시 말하지만, 주로 스타일 선택입니다.</li> + <li>{{htmlelement("tbody")}} 내부의 표 셀에서 텍스트를 가운데 정렬하여 제목과 일치하도록 했습니다. 기본적으로, 셀에는 {{cssxref("text-align")}} 에 <code>left</code> 값이 제공되고, 머리글에는 <code>center</code> 값이 제공되지만 둘 다에 대해 정렬을 동일하게 설정하는것이 좋습니다. 제목 글꼴의 기본 굵은체는 모양을 구별하기에 충분합니다.</li> + <li>데이터와 시작적으로 더 잘 연결되도록 {{htmlelement("tfoot")}} 내부에서 제목을 오른쪽 정렬했습니다.</li> +</ul> + +<p>결과는 조금 깔끔해 보입니다:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13072/table-with-typography.png" style="display: block; margin: 0 auto;"></p> + +<h3 id="그래픽_과_색상">그래픽 과 색상</h3> + +<p>이제 그래픽과 색상으로 넘어가겠습니다! 표에는 punk and attitude 가 가득하기 때문에, 밝은 인상적인 스타일링을 제공해야합니다. 걱정하지 마십시오. 표를 크게 만들 필요는 없습니다 — 더 미묘하고 세련된 것을 선택할 수 있습니다.</p> + +<p>아래에서 다시 CSS 를 <code>style.css</code> 파일에 추가하고, 다시 시작하십시오:</p> + +<pre class="brush: css">thead, tfoot { + background: url(leopardskin.jpg); + color: white; + text-shadow: 1px 1px 1px black; +} + +thead th, tfoot th, tfoot td { + background: linear-gradient(to bottom, rgba(0,0,0,0.1), rgba(0,0,0,0.5)); + border: 3px solid purple; +} +</pre> + +<p>다시 말하지만, 여기에는 표에만 해당되는 것이 없지만, 몇 가지 주목할 가치가 있습니다.</p> + +<p>{{htmlelement("thead")}} 및 {{htmlelement("tfoot")}} 에 {{cssxref("background-image")}} 를 추가하고, 머리글과 바닥글에 있는 모든 텍스트의 {{cssxref("color")}} 를 흰색으로 (텍스트에 그림자 추가) 변경하여 읽기 쉽게 했습니다. 텍스트가 배경과 잘 대비되도록 해야합니다. 그래야 잘 읽을 수 있습니다.</p> + +<p>또한 머리글과 바닥글 내부의 {{htmlelement("th")}} 및 {{htmlelement("td")}} 요소에 선형 그라데이션을 추가하여 약간의 질감을 개선하오, 밝은 보라색 테두리를 부여했습니다. 중첩된 요소를 여러 개의 중첩된 요소를 사용하여 스타일을 서로 겹칠 수 있는 것이 유용합니다. 예, 여러 배경 이미지를 사용하여 {{htmlelement("thead")}} 및 {{htmlelement("tfoot")}} 요소에 배경 이미지와 선형 그라데이션을 모두 넣을 수는 있지만, 별도로 결정했습니다. 여러 배경 이미지 또는 선형 그라데이션을 지원하지 않는 구형 브라우저의 이점을 위해서입니다.</p> + +<h4 id="얼룩말_줄무늬_Zebra_striping">얼룩말 줄무늬 (Zebra striping)</h4> + +<p>우리는 표의 다른 데이터 행을 더 쉽게 구문 분석하고 읽을 수 있도록 번갈아 가며 <strong>zebra stripes </strong>를 구현하는 방법을 보여주기 위해 별도의 섹션을 제공하고자 했습니다. <code>style.css</code> 파일의 맨 아래에 다름 CSS 를 추가하십시오:</p> + +<pre class="brush: css">tbody tr:nth-child(odd) { + background-color: #ff33cc; +} + +tbody tr:nth-child(even) { + background-color: #e495e4; +} + +tbody tr { + background-image: url(noise.png); +} + +table { + background-color: #ff33cc; +}</pre> + +<ul> + <li>이전에는 {{cssxref(":nth-child")}} 선택자가 특정 자식 요소를 선택하는 데 사용되는 것을 보았습니다. 수식을 매개 변수로 제공할 수도 있으므로 일련의 요소를 선택합니다. 수식 <code>2n-1</code> 은 홀수 번째 자식 (1, 3, 5 등) 을 모두 선택하고 수식 <code>2n</code> 은 짝수 번째 자식 (2, 4, 6 등) 을 모두 선택합니다. 코드의 <code>odd</code> 및 <code>even</code> 키워드 조차도 앞에서 언급한 공식과 정확히 동일한 기능을 수행합니다. 이 경우 홀수 및 짝수 행에 다른 색상 (선정적인 색상) 을 부여합니다.</li> + <li>또한 모든 본문 행에 반복적인 배경 타일을 추가하여, 약간의 노이즈 (약간 시각적 왜곡이 있는 반투명 <code>.png</code>) 를 사용하여 질감을 제공했습니다.</li> + <li>마지막으로, <code>:nth-child</code> 선택자를 지원하지 않는 브라우저는 여전히 본문 행의 배경을 갖도록 전체 표에 단색 배경색을 지정했습니다.</li> +</ul> + +<p>이러한 색상은 다음과 같은 모양을 만듭니다:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13074/table-with-color.png" style="display: block; margin: 0 auto;"></p> + +<p>자, 이것은 여러분의 취향에 맞지 않을 수도 있습니다. 하지만 , 우리가 하려고하는 요점은 표가 지루하고 학문적일 필요는 없다는 것입니다.</p> + +<h3 id="caption_스타일링">caption 스타일링</h3> + +<p>표와 관련하여 마지막으로 해야할 일이 있습니다 — caption 에 스타일을 지정하는 일입니다. 이렇게 하려면, <code>style.css</code> 파일의 맨 아래에 다름을 추가하십시오:</p> + +<pre class="brush: css">caption { + font-family: 'Rock Salt', cursive; + padding: 20px; + font-style: italic; + caption-side: bottom; + color: #666; + text-align: right; + letter-spacing: 1px; +}</pre> + +<p><code>bottom</code> 값을 가진 {{cssxref("caption-side")}} 속성을 제외하고는 여기서 주목할만한 것이 없습니다. 이로 인해 caption 이 표의 맨 아래에 배치되고 다른 선언과 함께 최종 모양을 얻을 수 있습니다 (<a href="http://mdn.github.io/learning-area/css/styling-boxes/styling-tables/punk-bands-complete.html">punk-bands-complete.html</a> 참조):</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13076/table-with-caption.png" style="display: block; height: 357px; margin: 0px auto; width: 723px;"></p> + +<h2 id="적극적인_학습_나만의_표_스타일">적극적인 학습: 나만의 표 스타일</h2> + +<p>이 시점에서 표 HTML 예제 (또는 일부를 사용하십시오!) 를 가져와서 표보다 훨씬 더 나은 디자인과 장식을 갖도록 스타일을 지정하고 싶습니다.</p> + +<h2 id="표_스타일링_빠르게_하는_팁">표 스타일링 빠르게 하는 팁</h2> + +<p>다음 단계로 넘어가지 전에, 위에서 설명한 가장 유용한 요점에 대한 간단한 목록을 제공해야 한다고 생각했습니다:</p> + +<ul> + <li>표 마크 업을 가능한 한 간단하게 만들고, 유연한 작업을 유지하십시오 예: 백분유을 사용하여 디자인의 반응속도를 향상시킵니다.</li> + <li>{{cssxref("table-layout")}}<code>: fixed</code> 를 사용하여 제목 ({{htmlelement("th")}}) 에서 {{cssxref("width")}} 를 설정하여 열 너비를 쉽게 설정할 수 있는 예측 가능한 표 레이아웃을 작성합니다.</li> + <li>{{cssxref("border-collapse")}}<code>: collapse</code> 를 사용하여 표 요소 테두리를 서로 접어서 깔끔하게 만들 수 있습니다.</li> + <li>{{htmlelement("thead")}}, {{htmlelement("tbody")}} 및 {{htmlelement("tfoot")}} 를 사용하여 표를 논리적 덩어리로 나누고 CSS 를 적용할 추가 위치를 제공하십시오. 필요한 경우 서로 위에 스타일을 더 쉽게 레이어할 수 있습니다.</li> + <li>alternative 행을 읽기 쉽게 하려면 얼룩말 줄무늬를 사용합니다.</li> + <li>{{cssxref("text-align")}} 을 사용하여 {{htmlelement("th")}} 및 {{htmlelement("td")}} 텍스트를 정렬하여, 더 깜끔하고 쉽게 따라할 수 있도록 하십시오.</li> +</ul> + +<h2 id="요약">요약</h2> + +<p>지금 우리 뒤에 스타일링 표가 있기 때문에, 우리의 시간을 차지할 다른 것이 필요합니다. 다음 기사에서는 CSS 디버깅에 대해 살펴봅니다 — 레이아웃이 제대로 보이지 않거나 적용할 때 적용되지 않는 속성과 같은 문제를 해결하는 방법. 여기에는 브라우저 DevTools 를 사용하여 문제점에 대한 솔루션을 찾는 방법에 대한 정보가 포함됩니다.</p> + +<p>{{PreviousMenuNext("Learn/CSS/Building_blocks/Images_media_form_elements", "Learn/CSS/Building_blocks/Debugging_CSS", "Learn/CSS/Building_blocks")}}</p> + +<h2 id="이번_강의에서는">이번 강의에서는</h2> + +<ol> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance">계단식 및 상속</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors">CSS 선택자</a> + <ul> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Type_Class_and_ID_Selectors">Type, class 및 ID 선택자</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Attribute_selectors">속성 선택자</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Pseudo-classes_and_pseudo-elements">Pseudo-classes 및 pseudo-elements</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Combinators">결합자</a></li> + </ul> + </li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/The_box_model">박스 모델</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Backgrounds_and_borders">배경 및 테두리</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Handling_different_text_directions">다른 텍스트 방향 처리</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Overflowing_content">콘텐츠 overflow</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Values_and_units">값 과 단위</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Sizing_items_in_CSS">CSS 에서 항목 크기 조정</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Images_media_form_elements">이미지, 미디어 및 양식 요소</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Styling_tables">표 스타일링</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Debugging_CSS">CSS 디버깅</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Organizing">CSS 정리</a></li> +</ol> diff --git a/files/ko/learn/css/building_blocks/values_and_units/index.html b/files/ko/learn/css/building_blocks/values_and_units/index.html new file mode 100644 index 0000000000..e4f8ab52b4 --- /dev/null +++ b/files/ko/learn/css/building_blocks/values_and_units/index.html @@ -0,0 +1,388 @@ +--- +title: CSS 값 과 단위 +slug: Learn/CSS/Building_blocks/Values_and_units +translation_of: Learn/CSS/Building_blocks/Values_and_units +--- +<div>{{LearnSidebar}}{{PreviousMenuNext("Learn/CSS/Building_blocks/Overflowing_content", "Learn/CSS/Building_blocks/Sizing_items_in_CSS", "Learn/CSS/Building_blocks")}}</div> + +<p>CSS 에 사용된 모든 속성에는 해당 속성에 허용되는 값 이 있으며, MDN 의 속성 페이지를 보면 특성 속성에 유효한 값을 이해하는 데 도움이 됩니다. 이 레슨에서는 가장 일반적인 값 과 사용 단위를 살펴 보겠습니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">전제조건:</th> + <td>기본 컴퓨터 활용 능력, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Installing_basic_software">기본 소프트웨어 설치</a>, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Dealing_with_files">파일 작업</a> 에 대한 기본 지식, HTML 기본 사항 (<a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">HTML 소개</a> 학습) 및 , CSS 작동 방식 이해 (<a href="/en-US/docs/Learn/CSS/First_steps">CSS 첫 번째 단계</a> 학습)</td> + </tr> + <tr> + <th scope="row">목적:</th> + <td>CSS 속성에 사용되는 다양한 유형의 값과 단위에 대해 배우기.</td> + </tr> + </tbody> +</table> + +<h2 id="CSS_값이란_무엇인가">CSS 값이란 무엇인가?</h2> + +<p>CSS 사양과 MDN 의 속성 페이지에서 <code><a href="/en-US/docs/Web/CSS/color_value"><color></a></code> 또는 <code><a href="/en-US/docs/Web/CSS/length"><length></a></code>. 와 같이 꺽쇠 괄호로 묶여 있는 값을 찾을 수 있습니다. <code><color></code> 값이 특정 속성에 유효한 것으로 표시되면, <code><a href="/en-US/docs/Web/CSS/color_value"><color></a></code> 참조 페이지에 나열된대로 유효한 속성을 해당 속성의 값으로 사용할 수 있습니다.</p> + +<div class="blockIndicator note"> +<p><strong>참고</strong>: CSS 값을 <em>데이터 유형 </em>이라고 합니다. 용어는 기본적으로 상호 교환이 가능합니다 — CSS 에서 데이터 유형이라고 하는것을 볼 때, 실제로 가치를 말하는 멋진 방법입니다.</p> +</div> + +<div class="blockIndicator note"> +<p><strong>참고</strong>: 예, CSS 값은 CSS 속성과 구별하기 위해, 꺽쇠 괄호를 사용하여 표시되는 경향이 있습니다 (예: {{cssxref("color")}} 속성, <a href="/en-US/docs/Web/CSS/color_value"><color></a> 데이터 형식). CSS 데이터 형식과 HTML 요소도 꺽쇠 괄호를 사용하므로 혼동될 수 있지만, 이는 매우 다른 상황에서 사용됩니다.</p> +</div> + +<p>다음 예제에서는 키워드를 사용하여 머리글의 색상을 설정하고, <code>rgb()</code> 함수를 사용하여 배경을 설정했습니다:</p> + +<pre class="brush: css"><code>h1 { + color: black; + background-color: rgb(197,93,161); +} </code> +</pre> + +<p>CSS 값은 허용가능한 하위값 모음을 정의하는 방법입니다. 즉, <code><color></code> 가 유효한 것으로 표시되면 — 키워드, 16진수 값, <code>rgb()</code> 함수 등 어떤 색상값을 사용할 수 있는지 궁금할 필요가 없습니다. 사용 가능한 <code><color></code> 값은 브라우저에서 지원한다고 가정합니다. 각 값에 대한 MDN 페이지는 브라우저 지원에 대한 정보를 제공합니다. 예를 들어 <code><a href="/en-US/docs/Web/CSS/color_value"><color></a></code> 페이지를 보면 브라우저 호환성 섹션에 다양한 색상값 유형과 지원이 나열되어 있습니다.</p> + +<p>여러가지 가능한 값을 시험해 볼 수 있도록 예를 들어 자주 접할 수 있는 몇 가지 유형의 값과 단위를 살펴보겠습니다.</p> + +<h2 id="숫자_길이_및_백분율">숫자, 길이 및 백분율</h2> + +<p>CSS 에서 사용할 수 있는 다양한 숫자 데이터 형식이 있습니다. 다음은 모두 숫자로 분류됩니다:</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">데이터 형식</th> + <th scope="col">설명</th> + </tr> + </thead> + <tbody> + <tr> + <td><code><a href="/en-US/docs/Web/CSS/integer"><integer></a></code></td> + <td><code><integer></code> 은 <code>1024</code> 또는<code>-55</code> 와 같은 정수입니다.</td> + </tr> + <tr> + <td><code><a href="/en-US/docs/Web/CSS/number"><number></a></code></td> + <td><code><number></code> 는 10진수를 나타냅니다 — 소수점 이하의 소수 자릿수 (예: <code>0.255</code>, <code>128</code> 또는 <code>-1.2</code>) 가 있을 수도 있고 없을 수도 있습니다.</td> + </tr> + <tr> + <td><code><dimension></code></td> + <td><code><dimension></code> 은 예를 들어 <code>45deg</code>, <code>5s</code> 또는 <code>10px</code>. 과 같은 단위가 붙어있는 <code><number></code> 입니다. <code><dimension></code> 은 <code><a href="/en-US/docs/Web/CSS/length"><length></a></code>, <code><a href="/en-US/docs/Web/CSS/angle"><angle></a></code>, <code><a href="/en-US/docs/Web/CSS/time"><time></a></code> 및 <code><a href="/en-US/docs/Web/CSS/resolution"><resolution></a></code> 의 종류를 포함하는 카테고리입니다<a href="/en-US/docs/Web/CSS/resolution">.</a></td> + </tr> + <tr> + <td><code><a href="/en-US/docs/Web/CSS/percentage"><percentage></a></code></td> + <td><code><percentage></code> 는 다른 값의 일부, 예를 들어 <code>50%</code> 를 나타냅니다. 백분율 값은 항상 다른 수량을 기준으로 합니다. 예를 들어 요소의 길이는 부모 요소의 길이를 기준으로 합니다.</td> + </tr> + </tbody> +</table> + +<h3 id="길이">길이</h3> + +<p>가장 자주 사용되는 숫자 형식은 <code><length></code> 입니다. 예를 들면 <code>10px</code> (픽셀) 또는<code>30em</code>. CSS 에서 사용되는 길이는 — 상대 및 절대의 두 가지 유형이 있습니다. 얼마나 커질지 알기 위해서는 차이를 이해하는 것이 중요합니다.</p> + +<h4 id="절대_길이_단위">절대 길이 단위</h4> + +<p>다음은 모두 <strong>절대</strong> 길이 단위이며 — 다른 것과 관련이 없으며 일반적으로 항상 동일한 크기로 간주됩니다.</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">단위</th> + <th scope="col">이름</th> + <th scope="col">다음과 동일함</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>cm</code></td> + <td>센티미터</td> + <td>1cm = 96px/2.54</td> + </tr> + <tr> + <td><code>mm</code></td> + <td>밀리미터</td> + <td>1mm = 1/10th of 1cm</td> + </tr> + <tr> + <td><code>Q</code></td> + <td>4분의 1 밀리미터</td> + <td>1Q = 1/40th of 1cm</td> + </tr> + <tr> + <td><code>in</code></td> + <td>인치</td> + <td>1in = 2.54cm = 96px</td> + </tr> + <tr> + <td><code>pc</code></td> + <td>Picas</td> + <td>1pc = 1/16th of 1in</td> + </tr> + <tr> + <td><code>pt</code></td> + <td>포인트</td> + <td>1pt = 1/72th of 1in</td> + </tr> + <tr> + <td><code>px</code></td> + <td>픽셀</td> + <td>1px = 1/96th of 1in</td> + </tr> + </tbody> +</table> + +<p>이러한 값의 대부분은 화면 출력이 아닌 인쇄에 사용될 때 더 유용합니다. 예를 들어 일반적으로 화면에 <code>cm</code> (센티미터) 를 사용하지 않습니다. 보통 사용하는 유일한 값은 <code>px</code> (픽셀) 입니다.</p> + +<h4 id="상대_길이_단위">상대 길이 단위</h4> + +<p>상대 길이 단위는 다른 요소 (상위 요소의 글꼴 크기 또는 viewport 크기) 와 관련이 있습니다. 상대 단위를 사용하면 텍스트나 다른 요소의 크기가 페이지의 다른 모든 것에 비례하여 조정되도록 신중하게 계획할 수 있다는 이점이 있습니다. 웹 개발에 가장 유용한 단위가 아래 표에 나열되어 있습니다.</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">단위</th> + <th scope="col">관련 사항</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>em</code></td> + <td>요소의 글꼴 크기.</td> + </tr> + <tr> + <td><code>ex</code></td> + <td>요소 글꼴의 x-height.</td> + </tr> + <tr> + <td><code>ch</code></td> + <td>요소 글꼴의 glyph "0" 의 사전 길이 (너비) 입니다.</td> + </tr> + <tr> + <td><code>rem</code></td> + <td>루트 요소의 글꼴 크기.</td> + </tr> + <tr> + <td><code>lh</code></td> + <td>요소의 라인 높이.</td> + </tr> + <tr> + <td><code>vw</code></td> + <td>viewport 너비의 1%.</td> + </tr> + <tr> + <td><code>vh</code></td> + <td>viewport 높이의 1%.</td> + </tr> + <tr> + <td><code>vmin</code></td> + <td>viewport 의 작은 치수의 1%.</td> + </tr> + <tr> + <td><code>vmax</code></td> + <td>viewport 의 큰 치수의 1%.</td> + </tr> + </tbody> +</table> + +<h4 id="예제_살펴보기">예제 살펴보기</h4> + +<p>아래 예에서 일부 상대 및 절대 길이 단위의 동작을 확인할 수 있습니다. 첫 번째 박스에는 {{cssxref("width")}} 픽셀 단위로 설정되어 있습니다. 절대 단위로서 이 너비는 다른 사항에 관계없이 동일하게 유지됩니다.</p> + +<p>두 번째 박스의 너비는 <code>vw</code> (viewport 너비) 단위로 설정됩니다. 이 값은 viewport 너비를 기준으로 하므로, 10vw 는 viewport 너비의 10% 입니다. 브라우저 창의 너비를 변경하면, 박스의 크기가 변경되지만, 이 예제는 <code><a href="/en-US/docs/Web/HTML/Element/iframe"><iframe></a></code> 을 사용하여 페이지에 포함되므로 작동하지 않습니다. 이 기능을 실제로 보려면 <a href="https://mdn.github.io/css-examples/learn/values-units/length.html">브라우저 탭에서 예제를 연 후 에 시도</a> 해야 합니다.</p> + +<p>세 번째 박스는 <code>em</code> 단위를 사용합니다. 글꼴 크기에 상대적입니다. <code>.wrapper</code> class 를 포함하는 {{htmlelement("div")}} 를 포함하여 글꼴 크기를 <code>1em</code> 으로 설정했습니다. 이 값을 <code>1.5em</code> 으로 변경하면 모든 요소의 글꼴 크기가 증가하지만, 너비가 해당 글꼴 크기에 비례하므로 마지막 항목만 넓어집니다.</p> + +<p>위의 지침을 따른 후 다른 방법으로 값을 실습하여 얻은 것을 확인하십시오.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/values-units/length.html", '100%', 820)}}</p> + +<h4 id="ems_및_rems">ems 및 rems</h4> + +<p><code>em</code> 과 <code>rem</code> 은 박스에서 텍스트로 크기를 조정할 때 가장 자주 발생하는 두 개의 상대 길이입니다. <a href="/en-US/docs/Learn/CSS/Styling_text">텍스트 스타일링</a> 또는 <a href="/en-US/docs/Learn/CSS/CSS_layout">CSS 레이아웃</a> 과 같은 보다 복잡한 주제를 시작할 때, 이러한 작동 방식과 차이점을 이해하는 것이 좋습니다. 아래 예제는 데모를 제공합니다.</p> + +<p>HTML 은 중첩된 목록의 집합니다 — 총 3개의 목록이 있으며 두 예제 모두 동일한 HTML 을 갖습니다. 유일한 차이점은 첫 번째는 <strong><em>ems</em></strong> class 이고 두 번째는 <strong><em>rems</em></strong> class 입니다.</p> + +<p>먼저, <code><html></code> 요소에서 글꼴 크기로 16px 를 설정합니다.</p> + +<p><strong>다시 말해서, em 단위는 "부모 요소의 글꼴 크기" 를 의미합니다</strong>. <code>ems</code> <code>class</code> 가 있는 {{htmlelement("ul")}} 내부의 {{htmlelement("li")}} 요소는 부모로부터 크기를 가져옵니다. 따라서 각 중첩 부분은 글꼴 크기가 부모 글꼴 크기의 <code>1.3em</code> — 1.3 배로 설정되므로 점점 더 커집니다.</p> + +<p><strong>다시 말해서, rem 단위는 "루트 요소의 글꼴 크기" 를 의미합니다</strong>. ("root em" 의 rem 표준입니다.) <code>rems</code> <code>class</code> 가 있는 {{htmlelement("ul")}} 내부의 {{htmlelement("li")}} 요소는 루트 요소는 (<code><html></code>) 에서 크기를 가져옵니다. 이것은 각각의 연속적인 중첩 부분이 계속 커지는 것을 의미합니다.</p> + +<p>그러나, CSS 에서 <code><html></code> <code>font-size</code> 를 변경하면 다른 모든 텍스트가 변경되는 것을 볼 수 있습니다 — <code>rem</code>- 및 <code>em</code>-크기 텍스트.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/values-units/em-rem.html", '100%', 1000)}} </p> + +<h3 id="백분율">백분율</h3> + +<p>많은 경우 백분율은 길이와 같은 방식으로 처리됩니다. 백분율이 있는 것은 항상 다른 값에 상대적으로 설정된다는 것입니다. 예를 들어, 요소의 <code>font-size</code> 를 백분율로 설정하면요소 무보의 글꼴 크기에 대한 백분율이 됩니다. <code>width</code> 값에 백분율을 사용하면, 부모 너비의 백분율이 됩니다.</p> + +<p>아래 예제에서 두 개의 백분율 크기 박스와 두 개의 픽셀 크기 박스는 동일한 class 이름을 갖습니다. 두 세트의 너비는 각각 200px 및 40% 입니다.</p> + +<p>차이점은 두 박스의 두 번째 세트가 너비가 400 픽셀 안에 있다는 것입니다. 두 번째 200px 너비의 박스는 첫 번째 너비와 동일한 너비이지만, 두 번째 40% 박스는 이제 400px 의 40% 이므로 — 첫 번째 박스보다 훨씬 좁습니다!</p> + +<p><strong>너비 또는 백분율 값을 변경하여 작동 방식을 확인합니다.</strong></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/values-units/percentage.html", '100%', 850)}} </p> + +<p>다음 예제에서는 글꼴 크기가 백분율로 설정되어 있습니다. 각 <code><li></code> 의 <code>font-size</code> 는 80% 이므로, 중첩된 목록 항목은 부모로부터 크기를 상속함에 따라 점차 작아집니다.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/values-units/percentage-fonts.html", '100%', 650)}} </p> + +<p>많은 값이 길이 또는 백분율을 허용하지만, 길이만 허용하는 값도 있습니다. MDN 속성 참조 페이지에서 어떤 값이 허용되는지 확인할 수 있습니다. 허용된 값에 <code><a href="/en-US/docs/Web/CSS/length-percentage"><length-percentage></a></code> 가 포함된 경우 길이 또는 백분율을 사용할 수 있습니다. 허용된 값에 <code><length></code> 만 포함된 경우, 백분율을 사용할 수 없습니다.</p> + +<h3 id="숫자">숫자</h3> + +<p>일부 값은 단위를 추가하지 않고 숫자를 허용합니다. 단위가 없는 숫자를 허용하는 속성의 예는 요소의 불투명도 (투명한 정도) 를 제어하는 <code>opacity</code> 속성입니다. 이 속성은 <code>0</code> (완전 투명) 과 <code>1</code> (완전 불투명) 사이의 숫자를 허용합니다.</p> + +<p><strong>아래 예제에서, <code>opacity</code> 값을 <code>0</code> 과 <code>1</code> 사이의 다양한 10진수 값으로 변경하고 박스와 그 내용이 어떻게 붙투명하게 되는지 확인하십시오.</strong></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/values-units/opacity.html", '100%', 500)}} </p> + +<div class="blockIndicator note"> +<p><strong>참고</strong>: CSS 에서 숫자를 값으로 사용하는 경우 따옴표로 묶지 않아야합니다.</p> +</div> + +<h2 id="색상">색상</h2> + +<p>CSS 에서 색상을 지정하는 방법은 여러가지가 있으며, 그 중 일부는 다른것 보다 최근에 구현되었습니다. 텍스트 색상, 배경 색상 등을 지정하든 상관없이 CSS 의 모든 위치에서 동일한 색상 값을 사용할 수 있습니다.</p> + +<p>최신 컴퓨터에서 사용할 수 있는 표준 색상 시스템은 24bit 이며, 채널당 256개의 서로 다른 값 (256 x 256 x 256 = 16,777,216.) 을 갖는 서로 다른 빨강, 녹색 및 파랑 채널의 조합을 통해 약 1670만개의 고유한 색상을 표시할 수 있습니다. CSS 에서 색상을 지정할 수 있는 몇 가지 방법을 살펴보겠습니다.</p> + +<div class="blockIndicator note"> +<p><strong>참고</strong>: 이 자습서에서는 브라우저 지원 기능이 우수한 색상을 지정하는 일반적인 방법을 살펴봅니다. 다른 것도 있지만, 지원 기능이 뛰어나지 않고 덜 일반적입니다.</p> +</div> + +<h3 id="색상_키워드">색상 키워드</h3> + +<p>여기의 학습 섹션이나 MDN 의 다른 예에서 색상 키워드를 지정하는 간단하고 이해하기 쉬운 방법인 색상 키워드를 볼 수 있습니다. 이 키워드에는 여러가지가 있으며 그중 일부는 상당히 재미있는 이름을 가지고 있습니다! <code><a href="/en-US/docs/Web/CSS/color_value"><color></a></code> 값에 대한 전체 목록을 페이지에서 볼 수 있습니다.</p> + +<p><strong>아래의 라이브 예제에서 다른 색상 값을 사용하여 작동하는 방법에 대한 아이디어를 얻으십시오.</strong></p> + +<h3 id="16진수_RGB_값">16진수 RGB 값</h3> + +<p>다음 형식의 색상 값은 16진수 코드입니다. 각 16진수 값은 hash/pound 기호 (#) 와 6개의 16진수로 구성되며, 각 16진수는 0 과 f (15를 나타냄) 사이의 16개 값 중 하나를 사용할 수 있으므로 — <code>0123456789abcdef</code> 입니다. 각 값 쌍은 채널 중 하나 — 빨강, 녹색 및 파랑 — 을 나타내며 각각에 대해 256개의 사용 가능한 값 (16 x 16 = 256) 을 지정할 수 있습니다.</p> + +<p>이 값은 좀 더 복잡하고 이해하기 쉽지 않지만 기워드보다 훨씬 더 다양합니다 — 16진수 값을 사용하여 색상표에 사용하려는 색상을 나타낼 수 있습니다.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/values-units/color-hex.html", '100%', 700)}} </p> + +<p><strong>다시 한 번, 값을 변경하여 색상이 어떻게 다른지 확인하십시오. </strong></p> + +<h3 id="RGB_및_RGBA_값">RGB 및 RGBA 값</h3> + +<p>여기서 이야기 할 세 번째 방식은 RGB 입니다. RGB 값은 — <code>rgb()</code> 함수입니다 — 이 값은 16진수 값과 거의 같은 방식으로 색상의 빨강, 녹색 및 파랑 채널 값을 나타내는 세 개의 매개 변수가 제공됩니다. RGB 와의 차이점은 각 채널이 2개의 16진수가 아니라 0 과 255 사이의 10진수로 표현되어 — 다소 이해하기 쉽다는 것입니다.</p> + +<p>Let's rewrite our last example to use RGB colors:</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/values-units/color-rgb.html", '100%', 700)}} </p> + +<p>RGBA 색상을 사용할 수도 있습니다 — 이 색상은 RGB 색상과 정확히 같은 방식으로 작동하므로 RGB 값을 사용할 수 있지만, 색상의 알파 채널을 나타내는 네 번째 값이 있어 불투명도 (opacity) 를 제어합니다. 이 값을 <code>0</code> 으로 설정하면 색상이 완전히 투명해지는 반면, <code>1</code> 이면 완전히 불투명하게 됩니다. 그 사이의 값은 다른 수준의 투명성을 제공합니다.</p> + +<div class="blockIndicator note"> +<p><strong>참고</strong>: 색상에 알파 채널을 설정하면 앞에서 살펴본 {{cssxref("opacity")}} 속성을 사용하는 것과 한 가지 중요한 차이점이 있습니다. 불투명도를 사용하면 요소와 그 안에 있는 모든 것을 불투명하게 만드는 반면, RGBA 색상을 사용하면 불투명하게 지정한 색상만 만들어집니다.</p> +</div> + +<p>아래 예제에서 나는 색상 박스가 포함된 블록에 배경 이미지를 추가했습니다. 그런 다음 박스에 다른 불투명도 값을 갖도록 설정했습니다 — 알파 채널 값이 작을 때 배경이 더 잘 나타나는지 확인하십시오.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/values-units/color-rgba.html", '100%', 770)}}</p> + +<p><strong>이 예에서는, 알파 채널 값을 변경하여 색상 출력에 어떤 영향을 미치는지 확인하십시오. </strong></p> + +<div class="blockIndicator note"> +<p><strong>참고</strong>: 어떤 시점에서 최신 브라우저는 <code>rgba()</code> 와 <code>rgb()</code> 및 <code>hsl()</code> 과 <code>hsla()</code> (아래 참조) 가 서로의 순수 별칭이 되어 정확히 동일한 동작을 시작하도록 업데이트 되었습니다. 예를 들어<code>rgba()</code> 및 <code>rgb()</code> 는 모두 알파 채널 값이 있거나 없는 색상을 허용합니다. 위 예제의 <code>rgba()</code> 함수를 <code>rgb()</code> 로 변경하고 색상이 여전히 작동하는지 확인하십시오! 어떤 스타일을 사용하느냐에 따라 다르지만, 다른 기능을 사용하기 위해 불투명과 투명한 색상 정의를 분리하면 브라우저 지원이 약간 향상되고 코드에서 투명 색상이 정의되는 위치를 시각적으로 표시할 수 있습니다.</p> +</div> + +<h3 id="HSL_및_HSLA_값">HSL 및 HSLA 값</h3> + +<p>RGB 보다 약간 덜 지원되는 HSL 색상은 (이전 버전의 IE 에서는 지원되지 않음) 디자이너의 관심을 끈 후에 구현되었습니다. <code>hsl()</code> 함수는 빨강, 녹색 및 파랑 값 대신 색조 (hue), 채도 (saturation) 및 명도(lightness) 값을 받아들입니다. 이 값은 1670만 가지 색상을 구별하는 데 사용되지만 다른 방식으로 사용됩니다.</p> + +<ul> + <li><strong>색조 (Hue)</strong>: 색상의 기본 음영입니다. 0 에서 360 사이의 값을 사용합니다.</li> + <li><strong>채도 (Saturation)</strong>: 색상이 얼마나 포함되어 있습니까? 0–100% 사이의 값을 취합니다. 여기서 0은 색상이 없고 (회색 음영으로 표시됨), 100% 는 전체 색상 채도입니다.</li> + <li><strong>명도 (Lightness)</strong>: 색상이 얼마나 밝습니까? 0–100% 의 값을 받습니다. 여기서 0은 빛이 없고 (완전히 검은색으로 표시됨), 100% 는 완전한 빛 (완전히 흰색으로 표시됨) 입니다.</li> +</ul> + +<p>다음과 같이 HSL 색상을 사용하도록 RGB 예제를 업데이트 할 수 있습니다:</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/values-units/color-hsl.html", '100%', 700)}} </p> + +<p>RGB 에 RGBA 가 있는 것처럼, HSL 에는 HSLA 에 상응하는 것이 있으므로, 알파 채널을 지정할 수 있는 동일한 기능을 제공합니다. HSLA 색상을 사용하도록 RGBA 예제를 변경하여 아래에서 이것을 시연했습니다.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/values-units/color-hsla.html", '100%', 770)}} </p> + +<p>여러분의 프로젝트에서 이러한 색상 값을 사용할 수 있습니다. 대부분의 프로젝트에서 색상 팔레트를 결정한 다음 전체 프로젝트에서 해당 색상 — 선택한 색상 지정 방법 — 을 사용합니다. 색상 모델을 혼합하고 일치시킬 수 있지만, 일관성을 유지하려면 전체 프로젝트에서 동일한 모델을 사용하는 것이 가장 좋습니다!</p> + +<h2 id="이미지">이미지</h2> + +<p><code><a href="/en-US/docs/Web/CSS/image"><image></a></code> 데이터 형식은 이미지가 유효한 값인 경우 사용됩니다. 이것은 <code>url()</code> 함수 또는 gradient 를 통해 가리키는 실제 이미지 파일일 수 있습니다.</p> + +<p>아래 예제에서 CSS <code>background-image</code> 속성의 값으로 사용되는 이미지와 gradient 를 보여주었습니다.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/values-units/image.html", '100%', 740)}} </p> + +<div class="blockIndicator note"> +<p><strong>참고</strong>: <code><image></code> 에 대해 가능한 다른 값이 있지만 이 값은 최신이며 최신 브라우저 지원이 좋지 않습니다. <image> 데이터 형식을 읽으려면 MDN 페이지에서 <code><a href="/en-US/docs/Web/CSS/image"><image></a></code> 데이터 형식을 확인하십시오.</p> +</div> + +<h2 id="위치_Position">위치 (Position)</h2> + +<p><code><a href="/en-US/docs/Web/CSS/position_value"><position></a></code> 데이터 형식은 배경 이미지 (<code><a href="/en-US/docs/Web/CSS/background-position">background-position</a></code> 를 통해) 와 같은 항목을 배치하는 데 사용되는 2D 좌표를 나타냅니다. <code>top</code>, <code>left</code>, <code>bottom</code>, <code>right</code> 및 <code>center</code> 와 같은 키워드를 사용하여 항목을 2D 박스의 특정 범위에 맞춰 길이와 함께 박스의 위쪽 및 왼쪽 가장자리에서 offset 을 나타냅니다.</p> + +<p>일반적인 position 값은 두 가지 값으로 구성됩니다 — 첫 번째는 위치를 가로로 설정하고, 두 번째는 세로로 설정합니다. 한 축의 값만 지정하면 다른 축은 <code>center</code> 으로 설정됩니다.</p> + +<p>다음 예제에서는 키워드를 사용하여 container 의 위쪽과 오른쪽에서 40px 의 배경 이미지를 배치했습니다.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/values-units/position.html", '100%', 720)}} </p> + +<p><strong>이 값을 가지고 놀면서 이미지를 어떻게 밀어낼 수 있는지 확인하십시오.</strong></p> + +<h2 id="문자열_및_식별자_identifiers">문자열 및 식별자 (identifiers)</h2> + +<p>위의 예에서, 키워드가 값으로 (예: <code>red</code>, <code>black</code>, <code>rebeccapurple</code> 및 <code>goldenrod</code>, 와 같은 <code><color></code> 키워드) 사용되는 위치를 확인했습니다. 이러한 키워드는 CSS 가 이해하는 특수한 값인 <strong><em>식별자 (identifiers) </em></strong>로, 보다 정확하게 설명됩니다. 따라서 인용되지 않으며 — 문자열로 취급되지 않습니다.</p> + +<p>CSS 에서 문자열을 사용하는 장소가 있습니다. 예를 들면, <a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Pseudo-classes_and_pseudo-elements#Generating_content_with_before_and_after">생성된 콘텐츠를 지정할 때</a>. 이 경우 값은 문자열임을 보여주기 위해 인용됩니다. 아래 예제에서는 인용되지 않은 색상 키워드와 인용된 생성된 콘텐츠 문자열을 사용합니다.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/values-units/strings-idents.html", '100%', 550)}} </p> + +<h2 id="함수_Functions">함수 (Functions)</h2> + +<p>우리가 살펴볼 마지막 값의 형식은 함수로 알려진 값의 그룹입니다. 프로그래밍에서 함수는 개발자와 컴퓨터 모두에서 최소한의 노력으로 반복적인 작업을 완료하기 위해 여러번 실행할 수 있는 재사용 가능한 코드 섹션입니다. 함수는 일반적으로 JavaScript, Python 또는 C++ 과 같은 언어와 관련이 있지만, 속성 값으로 CSS 에도 존재합니다 — <code>rgb()</code>, <code>hsl()</code> 등의 색상 섹션에서 작동하는 함수를 이미 보았습니다. 파일에서 이미지를 반환하는 데 사용되는 값인 — <code>url()</code> — 도 함수입니다.</p> + +<p>전통적인 프로그래밍 언어에서 찾아볼 수 있는 것과 비슷한 값은 <code>calc()</code> CSS 함수입니다. 이 함수를 사요하면 CSS 내에서 간단한 계산을 수행할 수 있습니다. 프로젝트의 CSS 를 작성할 때 정의할 수 없는 값을 계산하고 런타임에 브라우저가 작동해야하는 경우 특히 유용합니다.</p> + +<p>예를 들어, 아래에서는 <code>calc()</code> 를 사용하여 박스를 <code>20% + 100px</code> 너비로 만듭니다. 20% 는 부모 container <code>.wrapper</code> 의 너비에서 계산되므로 너비가 변경되면 변경됩니다. 우리는 부모 요소의 20% 가 무엇인지 알지 못하기 때문에, 이 계산을 미리 수행할 수 없으므로 <code>calc()</code> 를 사용하여 브라우저에 지시합니다.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/values-units/calc.html", '100%', 450)}}</p> + +<h2 id="요약">요약</h2> + +<p>이것은 가장 일반적인 형식의 값과 단위를 빠르게 살펴 보았습니다. <a href="/en-US/docs/Web/CSS/CSS_Values_and_Units">CSS 값 및 단위</a> 참조 페이지에서 다양한 유형을 모두 볼 수 있습니다. 이 수업을 진행하면서 사용중인 많은 것들을 보게 될 것입니다.</p> + +<p>기억해야 할 중요한 점은 각 속성에 정의된 값 목록이 있고 각 값에는 하위 값이 무엇인지 설명하는 정의가 있다는 것입니다. 그런 다음 MDN 에서 세부 사항을 찾을 수 있습니다.</p> + +<p>예를 들어, <code><a href="/en-US/docs/Web/CSS/image"><image></a></code> 를 사용하면 색상 gradient 를 만들 수 있다는 점을 이해하면 유용하지만 명백하지 않은 지식이 있을 수 있습니다!</p> + +<p>{{PreviousMenuNext("Learn/CSS/Building_blocks/Overflowing_content", "Learn/CSS/Building_blocks/Sizing_items_in_CSS", "Learn/CSS/Building_blocks")}}</p> + +<h2 id="이번_강의에서는">이번 강의에서는</h2> + +<ol> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance">계단식 및 상속</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors">CSS 선택자</a> + <ul> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Type_Class_and_ID_Selectors">Type, class 및 ID 선택자</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Attribute_selectors">속성 선택자</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Pseudo-classes_and_pseudo-elements">Pseudo-classes 및 pseudo-elements</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Combinators">결합자</a></li> + </ul> + </li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/The_box_model">박스 모델</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Backgrounds_and_borders">배경 및 테두리</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Handling_different_text_directions">다른 텍스트 방향 처리</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Overflowing_content">콘텐츠 overflow</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Values_and_units">값 과 단위</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Sizing_items_in_CSS">CSS 에서 항목 크기 조정</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Images_media_form_elements">이미지, 미디어 및 양식 요소</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Styling_tables">표 스타일링</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Debugging_CSS">CSS 디버깅</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Organizing">CSS 정리</a></li> +</ol> diff --git a/files/ko/learn/css/building_blocks/상자_모델/index.html b/files/ko/learn/css/building_blocks/상자_모델/index.html new file mode 100644 index 0000000000..aafc0a5241 --- /dev/null +++ b/files/ko/learn/css/building_blocks/상자_모델/index.html @@ -0,0 +1,347 @@ +--- +title: 상자 모델 +slug: Learn/CSS/Building_blocks/상자_모델 +tags: + - 디스플레이 + - 상자 모델 + - 씨에스에스 + - 여백 + - 초보자 + - 테두리 + - 패딩 + - 학습 +translation_of: Learn/CSS/Building_blocks/The_box_model +--- +<div>{{LearnSidebar}}{{PreviousMenuNext("Learn/CSS/Building_blocks/Selectors/Combinators", "Learn/CSS/Building_blocks/Backgrounds_and_borders", "Learn/CSS/Building_blocks")}}</div> + +<p>씨에스에스에 포함되는 모든 요소의 외장은 상자이며, 이 상자를 이해하는 것은 씨에스에스 조판을 생성하거나, 항목을 다른 항목과 대비해 정렬 능력을 갖추게 해주는 열쇠입니다. 이번 단원에서 우리는 씨에스에스 <em>상자 모델</em>을 제대로 살펴보겠습니다. 상자의 작동 방식과 상자와 관련된 용어를 이해함으로써 더 복잡한 조판 작업으로 넘어갈 수 있도록합니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">선결 사항:</th> + <td>기본 컴퓨터 활용 능력<a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Installing_basic_software">기본 소프트웨어 설치</a>, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Dealing_with_files">파일 작업에 대한 기본 지식</a>, 에이치티엠엘 기본기 (<a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">에이치티엠엘</a> 학습), 씨에스에스 작동 방식에 대한 개념 (<a href="/en-US/docs/Learn/CSS/First_steps">씨에스에스 첫 단계</a> 학습.) 등에 대한 기본 지식</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>씨에스에스 상자 모델, 상자 모델을 구성하고 대체 모델로 전환하는 방법에 대해 학습합니다.</td> + </tr> + </tbody> +</table> + +<h2 id="블록_및_인라인_상자">블록 및 인라인 상자</h2> + +<p>씨에스에스에는 크게 두 가지 상자(<strong>블록 상자</strong>와 <strong>인라인 상자</strong>) 유형이 있습니다. 이러한 특성은 상자가 페이지 대열 측면 및 페이지의 다른 상자와 관련하여 상자의 작동 방식을 나타냅니다.</p> + +<p>상자가 블록으로 정의되면 다음과 같은 방식으로 동작합니다:</p> + +<ul> + <li>상자는 인라인 방향으로 연장되어 상위 콘테이너에서 사용 가능한 공간을 채웁니다. 대부분은 경우 이것은 상자가 사용 가능한 공간을 100%로 채우면서 상위 콘테이너 너비만큼 된다는 의미입니다.</li> + <li>상자는 새 줄로 행갈이를 합니다.</li> + <li>{{cssxref("width")}}와 {{cssxref("height")}} 속성은 존중됩니다.</li> + <li>패딩과 여백, 테두리로 인해 다른 요소들이 상자로부터 밀려납니다.</li> +</ul> + +<p>여러분이 디스플레이 유형은 인라인으로 변경하지 않는 한 머리글(<code><h1></code>)과 <code><p></code>)와 같은 요소는 모두 기본값으로 외부 디스플레이 유형을 <code>block</code> 사용합니다.</p> + +<p>상자의 외부 디스플레이 유형이 <code>inline</code>일 경우:</p> + +<ul> + <li>상자는 새 줄로 행갈이를 하지 않습니다.</li> + <li>{{cssxref("width")}}와 {{cssxref("height")}} 속성은 적용되지 않습니다.</li> + <li>패딩과 여백, 테두리는 다른 인라인 상자들이 당 상자로부터 멀어지지게 하지 않습니다.</li> +</ul> + +<p>링크용 <code><a></code> 요소와 <code><span></code>, <code><em></code> 및 <code><strong></code> 요소는 모두 기본적으로 인라인으로 표시됩니다.</p> + +<p>요소에 적용되는 상자 유형은 <code>block</code> 및 <code>inline</code>과 같은 {{cssxref("display")}} 속성 값으로 정의되며. 아울러 그것은 <code>display</code>의 <strong>outer</strong> 값과 관련이 있습니다.</p> + +<h2 id="구분_내부_및_외부_디스플레이_유형">구분: 내부 및 외부 디스플레이 유형</h2> + +<p>이 시점에 우리는 <strong>내부</strong> 및 <strong>외부</strong> 디스플레이 유형에 대해 설명하는 게 좋겠습니다. 위에서 언급했듯이 씨에스에스의 상자는 <em>외부</em> 디스플레이 유형을 가지며, 이는 상자가 블록인지 인라인인지를 자세히 설명합니다.</p> + +<p>그러나 상자에는 <em>내부</em> 디스플레이 유형도 있으며 당 상자 내부의 요소가 배치되는 방법을 나타냅니다. 기본적으로 상자 내부의 요소는 <strong><a href="/en-US/docs/Learn/CSS/CSS_layout/Normal_Flow">일반 대열</a></strong>로 배치되며, 이는 (위에서 설명한 바와 같이) 여타 블록 및 인라인 요소와 마찬가지로 작동한다는 것을 의미합니다.</p> + +<p>그러나 여러분은 <code>flex</code>과 같은 <code>display</code> 값을 사용하여 내부 디스플레이 유형을 변경할 수 있습니다. 어떤 요소에 우리가 <code>display: flex;</code>를 설정하면 외부 디스플레이 유형은 블록이지만 내부 디스플레이 유형은 <ruby><code>flex</code><rp> (</rp><rt>가변</rt><rp>) </rp></ruby>으로 변경됩니다. 이 상자의 직계 자식은 가변 항목이 되고, 나중에 익히게 될 <a href="/ko/docs/Learn/CSS/CSS_layout/Flexbox">가변상자</a> 규격에 명시된 규칙에 따라 배치됩니다.</p> + +<div class="blockIndicator note"> +<p><strong>참고</strong>: 디스플레이 속성 값 및 상자가 블록 및 인라인 조판에서 작동하는 방법에 대해 자세히 보려면 <a href="/ko/docs/Web/CSS/CSS_Flow_Layout/Block_and_Inline_Layout_in_Normal_Flow">블록 및 인라인 조판</a>에 대한 모질라 개발자 네트워크 가이드를 참조하십시오.</p> +</div> + +<p>씨에스에스 조판에 대해 자세한 내용을 배우려면 다음번에는 예로 <code>flex</code>나 <code><a href="/ko/docs/Learn/CSS/CSS_layout/Grids">grid</a></code>같은 상자가 취할 수 있는 그 밖의 다양한 내부 속성 값을 마주치게 될 겁니다.</p> + +<p>그러나 블록 및 인라인 조판이 웹상에 사물이 행동하는 기본값입니다. 앞서 언급했듯이 그럴 일컬어 <ruby><em>normal flow</em><rp> (</rp><rt>일반 대열</rt><rp>) </rp></ruby>이라고 합니다. 그렇게 부르는 까닭은 다른 지시 사항이 없으면 상자는 블록 또는 인라인 상자로 배치되기 때문입니다.</p> + +<h2 id="서로_다른_디스플레이_유형의_예">서로 다른 디스플레이 유형의 예</h2> + +<p>계속해서 몇 가지 예를 살펴보겠습니다. 아래에 우리는 세 개의 서로 다른 에이치티엠엘 요소가 있으며, 모두 외부 디스플레이 유형이 <code>block</code>입니다. 첫 번째 단락은 씨에스에스에 테두리가 추가된 단락입니다. 브라우저는 이걸 블록 상자로 렌더링하므로 단락은 새 줄에서 시작되며 확보된 너비 전체까지 확장할 겁니다.</p> + +<p>두 번째는 <code>display: flex</code> 사용해 배치된 목록입니다. 이 예제는 컨테이너 내부의 항목에 대해 가변 조판을 수립하지만, 목록 자체는 블록 상자이며 단락과 같이 전체 컨테이너 너비로 확장되어 새 줄로 행갈이를 합니다.</p> + +<p>바로 아래에 우리는 블록 수준 단락을 하나 갖고 있으며 그 안에 두 개의 <code><span></code> 요소가 있습니다. 이들 요소는 보통 <code>inline</code>이겠지만, 그 중 하나에 블록 클래스에 있습니다. 우리가 그걸 미리 <code>display: block</code>로 설정했으니까요.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/box-model/block.html", '100%', 1000)}}</p> + +<p>우리는 다음 예제에서 <code>inline</code> 요소가 어떻게 동작하는지 볼 수 있습니다. 첫 번째 단락에서 <code><span></code>는 기본값으로 인라인으므로 새 줄 행갈이를 강제하지 않습니다.</p> + +<p><code>display: inline-flex</code>로 설정된 <code><ul></code> 요소도 갖고 있는데, 이는 몇 가지 가변 항목 주변에 인라인 상자를 생성합니다.</p> + +<p>마지막으로 <code>display: inline</code>으로 설정된 두 단락이 있습니다. 인라인 가변 컨테이너와 단락은 모두 하나의 라인에서 하나로 진행하지 블록 수준 요소처럼 표시하기 위해 새 줄로 행갈이를 하지 않습니다.</p> + +<p><strong>예제에서 여러분은 <code>display: inline</code> 부분을 <code>display: block</code>으로, 또는 <code>display: inline-flex</code>를 <code>display: flex</code>로 디스플레이 모드 사이를 전환할 수 있습니다.</strong></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/box-model/inline.html", '100%', 1000)}}</p> + +<p>나중에 해당 단원에서 가변 조판과 같은 것들을 접하게 될 것입니다. 당장 기억해야 할 핵심은 <code>display</code> 속성 값을 변경하면 상자의 외부 디스플레이 유형이 블록인지 인라인인지를 변경하여, 조판 속 다른 요소 주위에 자신을 표시하는 방법이 달라진다는 것입니다.</p> + +<p>나머지 수업에서는 외부 디스플레이 유형에 집중할 것이다.</p> + +<h2 id="씨에스에스_박스_모델이란_무엇인가">씨에스에스 박스 모델이란 무엇인가?</h2> + +<p>전체 씨에스에스 상자 모델은 블록 상자에 적용되며, 인라인 상자는 상자 모델에 정의된 일부 동작만 사용합니다. 이 모델은 당신이 페이지에서 볼 수 있는 상자를 생성하기 위해 상자의 서로 다른 부분인 여백, 테두리, 패딩 및 콘텐츠등이 어떻게 함께 작동할 것인지를 정의합니다. 몇 가지 복잡성을 추가하기 위해 표준 및 대체 상자 모델이 있습니다.</p> + +<h3 id="상자의_구성">상자의 구성</h3> + +<p>씨에스에스 블록 상자 구성하기 위한 우리의 준비물은:</p> + +<ul> + <li><strong>콘텐츠 상자</strong>: 당신의 콘텐츠가 표시되는 영역으로 그 크기는 {{cssxref("width")}} and {{cssxref("height")}}와 같은 속성을 사용해서 정할 수 있습니다.</li> + <li><strong>패딩 상자</strong>: 패딩은 콘텐츠 주변을 마치 공백처럼 자리잡습니다. 패딩의 크기는 {{cssxref("padding")}}와 관련 속성을 사용해 제어할 수 있습니다.</li> + <li><strong>테두리 상자</strong>: 테두리 상자는 콘텐츠와 패딩까지 둘러쌉니다. 테두리의 크기와 스타일은 {{cssxref("border")}}와 관련 속성을 사용하여 제어할 수 있습니다.</li> + <li><strong>여백 상자</strong>: 여백은 가장 바깥 쪽 레이어로 콘텐츠와 패딩, 테두리를 둘러싸면서 당 상자와 다른 요소 사이 공백 역할을 합니다. 여백 상자의 크기는 {{cssxref("margin")}}와 관련 속성을 사용하여 제어될 수 있습니다.</li> +</ul> + +<p>아래 도표는 이들 레이어를 보여줍니다.</p> + +<p><img alt="Diagram of the box model" src="https://mdn.mozillademos.org/files/16558/box-model.png" style="height: 300px; width: 544px;"></p> + +<h3 id="표준_씨에스에스_상자_모델">표준 씨에스에스 상자 모델</h3> + +<p>표준 상자 모델에서 상자에서 <code>width</code>와 <code>height</code>를 부여하면 <em>content box</em>의 너비와 높이가 정의됩니다. 그런 다음 패딩과 테두리는 상자의 너비와 높이에 추가되여 상자가 점유하는 전체 크기가 정해집니다. 그 내용이 아래 이미지에서 제시되었습니다.</p> + +<p>우리는 상자의 <code>width</code>와 <code>height</code>, <code>margin</code>과 <code>border</code> 및 <code>padding</code> 씨에스에스 값이 다음과 같이 지정되어 있다고 간주합니다:</p> + +<pre class="brush: css">.box { + width: 350px; + height: 150px; + margin: 25px; + padding: 25px; + border: 5px solid black; +} +</pre> + +<p>표준 박스 모델을 사용하여 상자가 차지하는 공간은 실제로 너비 410px(350 + 25 + 25 + 5 + 5), 높이 210px(150 + 25 + 25 + 5 + 5)가 될 것인데, 양쪽 패딩과 테두리는 콘텐츠 상자에 사용되는 너비에 더해지기 때문입니다.</p> + +<p><img alt="Showing the size of the box when the standard box model is being used." src="https://mdn.mozillademos.org/files/16559/standard-box-model.png" style="height: 300px; width: 500px;"></p> + +<div class="blockIndicator note"> +<p><strong>참고</strong>: 여백은 상자의 실제 크기에 포함되지 않습니다. 물론 여백은 상자가 페이지에서 차지하는 총 공간에 영향을 미치지만, 상자의 외부 공간에만 영향을 미칩니다. 상자의 영역은 테두리에서 멈추게 됩니다. 여백으로 확장되지 않습니다.</p> +</div> + +<h3 id="대체_씨에스에스_상자_모델">대체 씨에스에스 상자 모델</h3> + +<p>상자의 실제 크기를 얻기 위해 테두리와 패딩을 추가하는 것이 다소 불편하다고 생각할 수 있습니다. 당신 말이 옳을 것입니다! 이러한 이유로 씨에스에스는 표준 상자 모델 이후 머지않아 대체 상자 모델이 도입되었습니다. 이 모델을 사용한다면 너비는 페이지에서 표시되는 상자 너비이므로 콘텐츠 영역 너비는 너비에서 패딩 및 테두리 너비를 뺀 너비입니다. 위에서 사용된 것과 동일한 씨에스에스를 아래 결과에 대입하면(폭 = 350px, 높이 = 150px)가 됩니다.</p> + +<p><img alt="Showing the size of the box when the alternate box model is being used." src="https://mdn.mozillademos.org/files/16557/alternate-box-model.png" style="height: 240px; width: 440px;"></p> + +<p>기본값으로 브라우저는 기본 상자 모델을 사용합니다. 요소에 대체 모델을 활성화하려면 거기에 <code>box-sizing: border-box</code>를 설정하여 그렇게 할 수 있습니다. 이렇게 하면 당신이 설정한 크기에 따라 정의된 영역만큼 테두리 상자가 점유하도록 브라우저에 전달할 수 있습니다.</p> + +<pre class="brush: css"><code>.box { + box-sizing: border-box; +} </code></pre> + +<p>모든 요소가 대체 상자 모델을 사용하길 원한다면, (그것이 개발자들의 흔한 선택이기도 합니다) <code><html></code> 요소에 <code>box-sizing</code> 속성을 설정한 다음 아래의 소예제에서 볼 수 있듯이 다른 모든 요소가 해당 값을 상속하도록 설정하십시요. 이런 내용의 뒷배경이 되는 생각을 이해하고 싶다면 <a href="https://css-tricks.com/inheriting-box-sizing-probably-slightly-better-best-practice/">상자 크기에 관한 씨에스에스 요령</a> 문서를 참조하십시오.</p> + +<pre class="brush: css"><code class="language-css"><span class="selector token">html</span> <span class="punctuation token">{</span> + <span class="property token">box-sizing</span><span class="punctuation token">:</span> border-box<span class="punctuation token">;</span> +<span class="punctuation token">}</span> +<span class="selector token">*, *<span class="pseudo-element token">::before</span>, *<span class="pseudo-element token">::after</span></span> <span class="punctuation token">{</span> + <span class="property token">box-sizing</span><span class="punctuation token">:</span> inherit<span class="punctuation token">;</span> +<span class="punctuation token">}</span></code></pre> + +<div class="blockIndicator note"> +<p><strong>참고</strong>: 흥미로운 기록이 있습니다. 인터넷 익스플로러는 기본적으로 대체 상자 모델로 사용되었으며 전환할 수있는 메커니즘이 없습니다.</p> +</div> + +<h2 id="상자_모델_부리기">상자 모델 부리기</h2> + +<p>아래 예제에서 당신은 상자 2개를 확인할 수 있습니다. 둘 다 <code>.box</code> 클래스에 해당하며 <code>width</code>, <code>height</code>, <code>margin</code>, <code>border</code>, <code>padding</code>에 대해 동일한 값이 주어졌습니다. 유일한 차이라면 두 번째 상자는 대체 상자 모델을 사용하도록 설정되었다는 겁니다.</p> + +<p><strong>당신은 (<code>.alternate</code> 클래스를 씨에스에스에 추가해) 두 번째 상자 크기를 변경해 첫 번째 상자의 너비와 높이와 일치하도록 할 수 있습니까?</strong></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/box-model/box-models.html", '100%', 1000)}}</p> + +<div class="blockIndicator note"> +<p><strong>참조</strong>: <a href="https://github.com/mdn/css-examples/blob/master/learn/solutions.md#the-box-model">여러분은 이곳에서 동 질문에 대한 답변을 확인할 수 있습니다.</a>.</p> +</div> + +<h3 id="브라우저_개발자도구를_사용해_상자_모델_보기">브라우저 개발자도구를 사용해 상자 모델 보기</h3> + +<p><a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">브라우저 개발자 도구</a>를 사용하면 상자 모델을 훨씬 쉽게 이해할 수 있습니다. 파이어폭스의 개발자 도구에서 요소를 검사하면 요소의 크기와 여백, 패딩 및 테두리를 볼 수 있습니다. 이 방법으로 요소를 검사하면 실제로 그것이 당신이 생각하는 크기인지를 알아낼 수 있어 좋은 방법입니다.</p> + +<p><img alt="Inspecting the box model of an element using Firefox DevTools" src="https://mdn.mozillademos.org/files/16560/box-model-devtools.png" style="height: 683px; width: 1150px;"></p> + +<h2 id="여백과_패딩과_테두리">여백과 패딩과 테두리</h2> + +<p>상술한 예제에서 여러분은 이미 {{cssxref("margin")}}과 {{cssxref("padding")}}, 그리고 {{cssxref("border")}}를 보았습니다. 이번 예제에서 사용된 속성은 <ruby><strong>약칭</strong><rp>(</rp><rt>shorthands</rt><rp>)</rp></ruby>으로 한꺼번에 상자의 사방면을 설정할 수 있게 해줍니다. 해당 약칭은 또한 동명의 정식 명칭 속성도 있어 상자의 사방면을 개별적으로 제어할 수 있도록 해줍니다.</p> + +<p>해당 속성에 대한 자세한 내용을 탐구해 봅시다.</p> + +<h3 id="여백">여백</h3> + +<p>여백은 상자 주변에 보이지 않는 공간입니다. 여백은 상자로부터 다른 요소를 밀어냅니다. 여백은 양수값 또는 음수값을 가질 수 있습니다. 상자 한쪽 측면에 음수값 여백을 설정하면 페이지의 다른 부분과 공백이 겹칠 수 있습니다. 여러분이 표준 또는 대체 상자 모델을 사용하든지 관계없이 표시되는 상자의 크기를 계산한 후에 항상 여백이 추가됩니다.</p> + +<p>우리는 {{cssxref("margin")}} 속성을 사용하여 요소의 사방 여백을 한번에 제어할 수 있으며, 마찬가지로 동명의 정식 명칭 속성을 사용하며 각변의 여백을 제어할 수 있습니다.</p> + +<ul> + <li>{{cssxref("margin-top")}}</li> + <li>{{cssxref("margin-right")}}</li> + <li>{{cssxref("margin-bottom")}}</li> + <li>{{cssxref("margin-left")}}</li> +</ul> + +<p><strong>아래 예제에서 여백 값을 변경하여 당 요소와 상위 컨테이너 요소 사이의 여백 생성 또는 공간 제거(음의 여백인 경우)로 인해 상자가 어떻게 밀려나는지 확인하십시오.</strong></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/box-model/margin.html", '100%', 1000)}}</p> + +<h4 id="여백_축소">여백 축소</h4> + +<p>여백 이해의 핵심은 여백 축소에 대한 개념입니다. 여백이 서로 맞닿은 두 개의 요소가 있으면 해당 여백은 합쳐져 하나의 여백이 됩니다. 그 중 가장 큰 여백의 크기가 됩니다.</p> + +<p>아래 예제에는 단락 두 개가 있습니다. 상위 단락은 <code>margin-bottom</code> 값이 50픽셀이 주어졌습니다. 두 번째 단락은 <code>margin-top</code> 값이 30픽셀이 주어졌습니다. 전체 여백은 합쳐져 축소되면서 실제 상자 사이 여백은 50픽셀이며, 두 가지 여백을 합계가 되지 않습니다.</p> + +<p><strong>여러분은 2번째 단락의 <code>margin-top</code> 값을 0으로 설정해 이를 시험해 볼 수 있습니다. 두 단락 사이 표시되는 여백은 변경되지 않을 것이며, 첫 번째 단락의 <code>bottom-margin</code>에 설정된 50픽셀은 유지됩니다.</strong></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/box-model/margin-collapse.html", '100%', 1000)}}</p> + +<p>여백이 축소될 때와 축소되지 않을 때를 말해주는 여러 가지 규칙이 있습니다. 자세한 내용은 <a href="/en-US/docs/Web/CSS/CSS_Box_Model/Mastering_margin_collapsing">여백 축소 정복</a>에 대한 자세한 페이지를 참조하십시오. 당장 기억해야 할 주안점은 마진 축소란 것이 벌어지고 있다는 점이다. 여백이 있는 공간을 생성하고도 여러분이 기대하는 만큼의 공간을 얻지 못한다면, 아마도 그것은 여백 축소 현상일 것입니다.</p> + +<h3 id="테두리">테두리</h3> + +<p>테두리는 상자의 여백과 패딩 사이에 그려집니다. 표준 상자 모델을 사용하는 경우 테두리의 크기가 상자의 <code>width</code>과 <code>height</code>에 추가됩니다. 대체 상자 모델을 사용하고 있는 경우, 테두리의 크기는 사용 가능한 <code>width</code>와 <code>height</code>의 일부를 점유함으로 콘텐츠 상자가 더 작아지게 됩니다.</p> + +<p>테두리를 스타일링의 경우 많은 속성이 있습니다. 4개의 테두리, 각 테두리에는 스타일, 너비 및 색상 등 당신이 변경하고 싶을만한 것들이 있습니다.</p> + +<p>당산은 당장에 {{cssxref("border")}} 속성을 사용해 4개의 테두리 스타일과 너비, 색상을 지정할 수 있습니다.</p> + +<p>테두리 사방면에 각각 너비와 색상, 스타일을 설정할 수 있습니다:</p> + +<ul> + <li>{{cssxref("border-top")}}</li> + <li>{{cssxref("border-right")}}</li> + <li>{{cssxref("border-bottom")}}</li> + <li>{{cssxref("border-left")}}</li> +</ul> + +<p>테두리 사방면에 색상, 스타일, 너비를 설정하려면 다음과 같이 사용하십시요:</p> + +<ul> + <li>{{cssxref("border-width")}}</li> + <li>{{cssxref("border-style")}}</li> + <li>{{cssxref("border-color")}}</li> +</ul> + +<p>테두리 일방 면만 색상과 스타일, 너비를 설정하려면 세분화된 정식명칙 속성 중의 하나를 사용할 수 있습니다.</p> + +<ul> + <li>{{cssxref("border-top-width")}}</li> + <li>{{cssxref("border-top-style")}}</li> + <li>{{cssxref("border-top-color")}}</li> + <li>{{cssxref("border-right-width")}}</li> + <li>{{cssxref("border-right-style")}}</li> + <li>{{cssxref("border-right-color")}}</li> + <li>{{cssxref("border-bottom-width")}}</li> + <li>{{cssxref("border-bottom-style")}}</li> + <li>{{cssxref("border-bottom-color")}}</li> + <li>{{cssxref("border-left-width")}}</li> + <li>{{cssxref("border-left-style")}}</li> + <li>{{cssxref("border-left-color")}}</li> +</ul> + +<p><strong>아래 예제에서 테두리를 생성하기 위해 다양한 약칭과 정식 명칭을 사용했습니다. 그것들의 작동 방식을 파악하기 위해 서로 다른 속성을 마음대로 부려보십시요. 테두리 속성에 대한 모질라 개발자 네트워크 페이지 페이지는 당신이 선택할 수 있는 다양한 테두리 스타일에 대한 정보를 제공합니다.</strong></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/box-model/border.html", '100%', 1000)}}</p> + +<h3 id="패딩">패딩</h3> + +<p>패딩은 테두리와 콘텐츠 영역 사이에 위치합니다. 여백과는 다르게 패딩은 음수의 크기를 가질 수 없어, 그 값은 0 또는 양수 값이여야 합니다. 여러분의 요소에 적용된 배경은 패딩 뒤에 표시됩니다.패딩의 전형적인 용도는 테두리에서 콘텐츠를 밀어내는 겁니다.</p> + +<p>우리는 {{cssxref("padding")}} 속성을 사용하여 요소의 사방면 패딩을 개별적으로 제어할 수 있으며, 마찬가지로 정식 명칭 속성을 사용하며 각변의 패딩을 제어할 수 있습니다.</p> + +<ul> + <li>{{cssxref("padding-top")}}</li> + <li>{{cssxref("padding-right")}}</li> + <li>{{cssxref("padding-bottom")}}</li> + <li>{{cssxref("padding-left")}}</li> +</ul> + +<p><strong>아래 예제에서 <code>.box</code>클래스에 대한 패딩값을 변경하면 상자와 관계하여 텍스트가 시작되는 지점이 달라지는지 볼 수 있습니다.</strong></p> + +<p><strong>여러분은 또한 <code>.container,</code> 클래스에 대한 패딩을 변경하여 컨테이너와 상자 사이 공간을 만들 수 있습니다. 패딩 변경은 모든 요소에 가능하며 테두리와 요소 내부 공간 사이에 공간을 만듭니다.</strong></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/box-model/padding.html", '100%', 800)}}</p> + +<h2 id="상자_모델과_인라인_상자">상자 모델과 인라인 상자</h2> + +<p>상술한 모든 내용은 블록 상자에도 100% 적용됩니다. 상술한 속성 중의 일부는 인라인 상자에도 적용할 수 있습니다. 예를 들어 <code><span></code>에 의해 생성된 속성도 그렇습니다.</p> + +<p>아래 예제에 한 단락 내부에 <code><span></code>가 있고 거기에 <code>width</code>와 <code>height</code>, 그리고 <code>margin</code>와 <code>border</code>를 적용했습니다. 여러분이 보시다시피 너비와 높이는 무시됩니다. 여백, 패딩 및 테두리는 존치되지만 다른 콘텐츠와 인라인 상자아의 관계를 변경하지 않으므로 패딩 및 테두리는 단락의 다른 단어와 겹칩니다.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/box-model/inline-box-model.html", '100%', 800)}}</p> + +<h2 id="인라인_블록_디스플레이_사용하기">인라인 블록 디스플레이 사용하기</h2> + +<p><code>inline</code>와 <code>block</code> 사이 중립 지대를 제공하는 <code>display</code> 속성의 하나로 특별한 값이 있습니다. 이 속성은 항목이 새 줄로 넘어가는 행갈이를 원치않지만, <code>width</code>와 <code>height</code>가 존중되고 앞서 보았듯이 겹침 현상을 피하길 원하는 경우에 유용합니다.</p> + +<p><code>display: inline-block</code> 속성이 딸린 요소는 우리가 이미 파악했던 것 블록 요소의 하위 집합입니다.</p> + +<ul> + <li><code>width</code>와 <code>height</code> 속성은 존중됩니다.</li> + <li><code>padding</code>와 <code>margin</code>과 <code>border</code> 속성으로 인해 다른 요소가 상자에서 밀려납니다.</li> +</ul> + +<p>그러나 새 줄로 행갈이를 하지 않고, <code>width</code>와 <code>height</code> 속성을 명시적으로 추가하는 경우에만 해당 요소의 콘텐츠보다 (동 상자가) 더 커질 뿐입니다.</p> + +<p><strong>다음 예제에서 우리는 <code><span></code> 요소에 <code>display: inline-block</code>를 추가했습니다. 스팬 요소 속성을 <code>display: block</code>로 변경하던가 추가했던 라인을 제거한 뒤 디스플레이 모델의 차이를 확인해 보십시요.</strong></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/box-model/inline-block.html", '100%', 800)}}</p> + +<p>여러분이 <code>padding</code>를 추가해 링크에 적중 영역을 확대하길 원하는 경우 이것이 유용할 수 있습니다. <code><a></code>는 <code><span></code>처럼 인라인 요소입니다. 여러분은 해당 요소에 <code>display: inline-block</code>을 사용해 패딩을 설정할 수 있으므로 사용자가 링크를 클릭할 수 있습니다.</p> + +<p>탐색 (메뉴)모음에서 꽤 자주 사용되는 것을 볼겁니다. 아래 탐색 모음은 가변상자를 사용해 행으로 표시되었으며, <code><a></code>를 마우스로 가리킬 때 <code>background-color</code>를 변경할 수 있도록 <code><a></code> 요소에 패딩 추기했습니다. 패딩은 <code><ul></code> 요소의 테두리와 겹치는 것처럼 보입니다. 그렇게 된 까닭은 <code><a></code>가 인라인 요소이기 때문입니다.</p> + +<p><strong><code>.links-list a</code> 선택기에 딸린 규칙에 <code>display: inline-block</code>를 추가하면, 다른 요소에 의한 패딩이 존중되므로 여러분은 이(겹치는) 문제가 해결되는 것을 보게될 것입니다.</strong></p> + +<p>{{EmbedGHLiveSample("css-examples/learn/box-model/inline-block-nav.html", '100%', 600)}}</p> + +<h2 id="요약정리">요약정리</h2> + +<p>박스 모델에 대해 이해해야 할 내용의 대부분입니다. 상자들이 조판에 어떻게 포함된 것인지 혼란스러워지면, 향후 여러분은 이번 단원을 다시 찾게을 수 있습니다.</p> + +<p>다음 단원에서는 <a href="/en-US/docs/Learn/CSS/Building_blocks/Backgrounds_and_borders">배경과 테두리</a>를 사용하여 평범한 보이는 상자를 더욱 흥미롭게 보이려면 어떤 방법이 있는지 살펴보겠습니다.</p> + +<p>{{PreviousMenuNext("Learn/CSS/Building_blocks/Selectors/Combinators", "Learn/CSS/Building_blocks/Backgrounds_and_borders", "Learn/CSS/Building_blocks")}}</p> + +<h2 id="이번_단위에는">이번 단위에는</h2> + +<ol> + <li><a href="/ko/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance">계단식 나열과 상속</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors">씨에스에스 선택기</a> + <ul> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Type_Class_and_ID_Selectors">유형과 클레스, 아이디 선택기 selectors</a></li> + <li><a href="/ko/docs/Learn/CSS/Building_blocks/Selectors/Attribute_selectors">딸린 속성 선택기</a></li> + <li><a href="/ko/docs/Learn/CSS/Building_blocks/Selectors/Pseudo-classes_and_pseudo-elements">의사 클래스와 의사 요소</a></li> + <li><a href="/ko/docs/Learn/CSS/Building_blocks/Selectors/Combinators">조합기</a></li> + </ul> + </li> + <li><a href="/ko/docs/Learn/CSS/Building_blocks/%EC%83%81%EC%9E%90_%EB%AA%A8%EB%8D%B8">상자 모델</a></li> + <li><a href="/ko/docs/Learn/CSS/Building_blocks/Backgrounds_and_borders">배경 및 테두리</a></li> + <li><a href="/ko/docs/Learn/CSS/Building_blocks/Handling_different_text_directions">서로 다른 텍스트 방향 처리</a></li> + <li><a href="/ko/docs/Learn/CSS/Building_blocks/Overflowing_content">대열이탈 콘텐츠</a></li> + <li><a href="/ko/docs/Learn/CSS/Building_blocks/Values_and_units">속성값과 단위</a></li> + <li><a href="/ko/docs/Learn/CSS/Building_blocks/Sizing_items_in_CSS">씨에스에스 항목 크기 설정</a></li> + <li><a href="/ko/docs/Learn/CSS/Building_blocks/Images_media_form_elements">이미지와 미디아, 양식 요소</a></li> + <li><a href="/ko/docs/Learn/CSS/Building_blocks/Styling_tables">테이블 스타일링</a></li> + <li><a href="/ko/docs/Learn/CSS/Building_blocks/Debugging_CSS">씨에스에스 디버깅</a></li> + <li><a href="/ko/docs/Learn/CSS/Building_blocks/Organizing">씨에스에스 체계화</a></li> +</ol> diff --git a/files/ko/learn/css/building_blocks/선택자/index.html b/files/ko/learn/css/building_blocks/선택자/index.html new file mode 100644 index 0000000000..7674063921 --- /dev/null +++ b/files/ko/learn/css/building_blocks/선택자/index.html @@ -0,0 +1,223 @@ +--- +title: CSS 선택자 +slug: Learn/CSS/Building_blocks/선택자 +translation_of: Learn/CSS/Building_blocks/Selectors +--- +<div>{{LearnSidebar}}{{PreviousMenuNext("Learn/CSS/Building_blocks/Cascade_and_inheritance", "Learn/CSS/Building_blocks/Selectors/Type_Class_and_ID_Selectors", "Learn/CSS/Building_blocks")}}</div> + +<p class="summary">{{Glossary("CSS")}} 에서, 선택자는 스타일을 지정할 웹 페이지의 {{glossary("HTML")}} 요소를 대상으로 하는 데 사용됩니다. 사용 가능한 다양한 CSS 선택자가 있으며, 스타일을 지정할 요소를 선택할 때 세밀한 정밀도를 허용합니다. 이 기사와 하위 기사에서는 다양한 유형을 자세히 살펴보고 작동 방식을 살펴보겠습니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">전제조건:</th> + <td>기본 컴퓨터 활용 능력, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Installing_basic_software">기본 소프트웨어 설치</a>, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Dealing_with_files">파일 작업</a> 에 대한 기본 지식, HTML 기본 사항 (<a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">HTML 소개</a> 학습) 및 CSS 작동 방식에 대한 이해 (<a href="/en-US/docs/Learn/CSS/First_steps">CSS 첫 단계</a> 학습)</td> + </tr> + <tr> + <th scope="row">목적:</th> + <td>CSS 선태자 작동 방식에 대해 자세히 알아보기.</td> + </tr> + </tbody> +</table> + +<h2 id="선택자란_무엇인가">선택자란 무엇인가?</h2> + +<p>이미 선택자 (selector) 를 만났습니다. CSS 선택자는 CSS 규칙의 첫 부분입니다. 규칙 내의 CSS 속성값을 적용하기 위해 어떤 HTML 요소를 선택해야 하는지 브라우저에 알려주는 요소 및 기타 용어의 패턴입니다. 선택자에 의해 선택된 요소들은 <em><strong>선택자의 주제(subject)</strong> </em>로 지칭됩니다.</p> + +<p><img alt="Some code with the h1 highlighted." src="https://mdn.mozillademos.org/files/16550/selector.png" style="border: 1px solid #cccccc; height: 218px; width: 471px;"></p> + +<p>이전 기사에서는 몇 가지 다른 선택자를 만났으며 — 예를 들어 <code>h1</code> 과 같은 요소 또는 <code>.special</code> 과 같은 class 를 선택하는 등 다양한 방법으로 문서를 대상으로 하는 선택자가 있다는 것을 배웠습니다.</p> + +<p>CSS 에서, 선택자는 CSS 선택자 사양에 정의되어 있습니다. CSS 의 다른 부분과 마찬가지로 작동하려면, 브라우저에서 지원해야합니다. 당신이 보게 될 대부분의 선택자는 <a href="https://www.w3.org/TR/selectors-3/">Level 3 선택자 사양</a> 에 정의되어 있으므로, 이러한 선택자에 대한 훌륭한 브라우저 지원을 찾을 수 있습니다.</p> + +<h2 id="선택자_목록">선택자 목록</h2> + +<p>동일한 CSS 를 사용하는 항목이 두 개 이상인 경우 규칙이 모든 개별 선택자에 적용되도록 개별 선택자를 <em><strong>선택자 목록</strong> </em>으로 결합할 수 있습니다. 예를 들어, <code>h1</code> 에 대해 동일한 CSS 와 <code>special</code> class 를 사용하면 이것을 두 개의 별도 규칙으로 작성할 수 있습니다.</p> + +<pre class="brush: css"><code>h1 { + color: blue; +} + +.special { + color: blue; +} </code></pre> + +<p>또한 이들 사이에 쉼표를 추가하여 선택자 목록으로 결합할 수도 있습니다.</p> + +<pre class="brush: css"><code>h1, .special { + color: blue; +} </code></pre> + +<p>공백은 쉼표 앞뒤에 유효합니다. 각 라인이 새 라인에 있으면 선택자를 더 읽기 쉽습니다.</p> + +<pre class="brush: css"><code>h1, +.special { + color: blue; +} </code></pre> + +<p>아래 라이브 예제에서 동일한 선언을 가진 두 선택자를 결합 하십시오. 시각적 디스플레이는 결합 후 동일해야 합니다.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/selectors/selector-list.html", '100%', 1000)}} </p> + +<p>이러한 방식으로 선택자를 그룹화할 때, 선택자가 유효하지 않은 경우 전체 규칙이 무시됩니다.</p> + +<p>다음 예에서는, 잘못된 class 선택자 규칙이 무시되고 <code>h1</code> 은 여전히 스타일이 지정됩니다.</p> + +<pre class="brush: css"><code>h1 { + color: blue; +} + +..special { + color: blue; +} </code></pre> + +<p>그러나 결합하면, 전체 규칙이 유효하지 않은 것으로 간주되어 <code>h1</code> 또는 class 가 스타일 지정되지 않습니다.</p> + +<pre class="brush: css"><code>h1, ..special { + color: blue; +} </code></pre> + +<h2 id="선택자의_유형">선택자의 유형</h2> + +<p>선택자에는 몇 가지 그룹이 있으며, 어떤 유형의 선택자가 필요한지 알면 작업에 적합한 도구를 찾는데 도움이 됩니다. 이 기사의 하위 기사에서는 다양한 선택자 그룹을 자세히 살펴 보겠습니다.</p> + +<h3 id="Type_class_및_ID_선택자">Type, class 및 ID 선택자</h3> + +<p>이 그룹에는 <code><h1></code> 과 같은 HTML 요소를 대상으로 하는 선택자가 포함됩니다.</p> + +<pre class="brush: css">h1 { }</pre> + +<p>또한 class 를 대상으로 하는 선택자가 포함됩니다:</p> + +<pre class="brush: css">.box { }</pre> + +<p>또는 ID:</p> + +<pre class="brush: css">#unique { }</pre> + +<h3 id="속성_선택자">속성 선택자</h3> + +<p>이 선택자 그룹은 요소에 특정 속성이 있는지에 따라 요소를 선택하는 다른 방법을 제공합니다:</p> + +<pre class="brush: css">a[title] { }</pre> + +<p>또는 특정 값을 가진 속성의 존재 여부를 기반으로 선택하십시오:</p> + +<pre class="brush: css">a[href="https://example.com"] { }</pre> + +<h3 id="Pseudo-classes_및_pseudo-elements">Pseudo-classes 및 pseudo-elements</h3> + +<p>이 선택자 그룹에는 요소의 특정 상태를 스타일링하는 pseudo-classes 가 포함됩니다. 예를 들어 <code>:hover</code> pseudo-class 는 마우스 포인터에 의해 요소를 가리킬 때만 요소를 선택합니다:</p> + +<pre class="brush: css">a:hover { }</pre> + +<p>또한 요소 자체가 아닌 요소의 특정 부분을 선택하는 pseudo-elements 도 포함됩니다. 예를 들어, <code>::first-line</code> 은 항상 <code><span></code> 이 첫 번째 형식의 라인을 감싸는 것처럼 작동하여, 요소 내부의 첫 번째 텍스트 라인 (아래의 경우 <code><p></code>) 을 선택합니다.</p> + +<pre class="brush: css">p::first-line { }</pre> + +<h3 id="결합자_Combinators">결합자 (Combinators)</h3> + +<p>최종 선택자 그룹은 문서 내의 요소를 대상으로 하기 위해 다른 선택자를 결합합니다. 예를 들어 다음은 자식 결합자 (<code>></code>) 를 사용하여 <code><article></code> 요소의 자식인 단락을 선택합니다:</p> + +<pre class="brush: css">article > p { }</pre> + +<h2 id="다음_단계">다음 단계</h2> + +<p>이 학습 섹션 또는 일반적으로 MDN 에서 다양한 유형의 선택자로 직접 연결되는 링크에 대해서는 아래의 선택자 참조 표를 참고하거나 <a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Type_Class_and_ID_Selectors">type, class 및 ID 선택자</a> 에 대해 계속해서 여행을 시작하십시오.</p> + +<p>{{PreviousMenuNext("Learn/CSS/Building_blocks/Cascade_and_inheritance", "Learn/CSS/Building_blocks/Selectors/Type_Class_and_ID_Selectors", "Learn/CSS/Building_blocks")}}</p> + +<h2 id="선택자_참조_표">선택자 참조 표</h2> + +<p>아래 표는 사용 가능한 선택자의 개요와 이 안내서의 페이지에 대한 링크와 함께 각 유형의 선택자 사용법을 보여줍니다. 브라우저 지원 정보를 확인할 수 있는 각 선택자의 MDN 페이지에 대한 링크도 포함되어 있습니다. 이 자료를 나중에 자료에서 선택자를 찾아 보거나, CSS 를 일반적으로 실험할 때 다시 참조할 수 있습니다.</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">선택자</th> + <th scope="col">예제</th> + <th scope="col">CSS 자습서 배우기</th> + </tr> + </thead> + <tbody> + <tr> + <td><a href="/en-US/docs/Web/CSS/Type_selectors">Type 선택자</a></td> + <td><code>h1 { }</code></td> + <td><a href="/en-US/docs/user:chrisdavidmills/CSS_Learn/CSS_Selectors/Type_Class_and_ID_Selectors#Type_selectors">Type selectors</a></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/CSS/Universal_selectors">범용 선택자</a></td> + <td><code>* { }</code></td> + <td><a href="/en-US/docs/user:chrisdavidmills/CSS_Learn/CSS_Selectors/Type_Class_and_ID_Selectors#The_universal_selector">The universal selector</a></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/CSS/Class_selectors">Class 선택자</a></td> + <td><code>.box { }</code></td> + <td><a href="https://developer.mozilla.org/en-US/docs/user:chrisdavidmills/CSS_Learn/CSS_Selectors/Type_Class_and_ID_Selectors#Class_selectors">Class selectors</a></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/CSS/ID_selectors">id 선택자</a></td> + <td><code>#unique { }</code></td> + <td><a href="https://developer.mozilla.org/en-US/docs/user:chrisdavidmills/CSS_Learn/CSS_Selectors/Type_Class_and_ID_Selectors#ID_Selectors">ID selectors</a></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/CSS/Attribute_selectors">속성 선택자</a></td> + <td><code>a[title] { }</code></td> + <td><a href="https://developer.mozilla.org/en-US/docs/User:chrisdavidmills/CSS_Learn/CSS_Selectors/Attribute_selectors">Attribute selectors</a></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/CSS/Pseudo-classes">Pseudo-class 선택자</a></td> + <td><code>p:first-child { }</code></td> + <td><a href="https://developer.mozilla.org/en-US/docs/User:chrisdavidmills/CSS_Learn/CSS_Selectors/Pseuso-classes_and_Pseudo-elements#What_is_a_pseudo-class">Pseudo-classes</a></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/CSS/Pseudo-elements">Pseudo-element 선택자</a></td> + <td><code>p::first-line { }</code></td> + <td><a href="https://developer.mozilla.org/en-US/docs/User:chrisdavidmills/CSS_Learn/CSS_Selectors/Pseuso-classes_and_Pseudo-elements#What_is_a_pseudo-element">Pseudo-elements</a></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/CSS/Descendant_combinator">하위 결합자</a></td> + <td><code>article p</code></td> + <td><a href="https://developer.mozilla.org/en-US/docs/User:chrisdavidmills/CSS_Learn/CSS_Selectors/Combinators#Descendant_Selector">Descendant combinator</a></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/CSS/Child_combinator">자식 결합자</a></td> + <td><code>article > p</code></td> + <td><a href="https://developer.mozilla.org/en-US/docs/User:chrisdavidmills/CSS_Learn/CSS_Selectors/Combinators#Child_combinator">Child combinator</a></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/CSS/Adjacent_sibling_combinator">인접 형제 결합자</a></td> + <td><code>h1 + p</code></td> + <td><a href="https://developer.mozilla.org/en-US/docs/User:chrisdavidmills/CSS_Learn/CSS_Selectors/Combinators#Adjacent_sibling">Adjacent sibling</a></td> + </tr> + <tr> + <td><a href="/en-US/docs/Web/CSS/General_sibling_combinator">일반 형제 결합자</a></td> + <td><code>h1 ~ p</code></td> + <td><a href="https://developer.mozilla.org/en-US/docs/User:chrisdavidmills/CSS_Learn/CSS_Selectors/Combinators#General_sibling">General sibling</a></td> + </tr> + </tbody> +</table> + +<h2 id="이번_강의에서는">이번 강의에서는</h2> + +<ol> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance">계단식 및 상속</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors">CSS 선택자</a> + <ul> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Type_Class_and_ID_Selectors">Type, class 및 ID 선택자</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Attribute_selectors">속성 선택자</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Pseudo-classes_and_pseudo-elements">Pseudo-classes 및 pseudo-elements</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors/Combinators">결합자</a></li> + </ul> + </li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/The_box_model">박스 모델</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Backgrounds_and_borders">배경 및 테두리</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Handling_different_text_directions">다른 텍스트 방향 처리</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Overflowing_content">콘텐츠 overflow</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Values_and_units">값과 단위</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Sizing_items_in_CSS">CSS 에서 항목 크기 조정</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Images_media_form_elements">이미지, 미디어 및 양식 요소</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Styling_tables">표 스타일링</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Debugging_CSS">CSS 디버깅</a></li> + <li><a href="/en-US/docs/Learn/CSS/Building_blocks/Organizing">CSS 정리</a></li> +</ol> diff --git a/files/ko/learn/css/css_layout/flexbox/index.html b/files/ko/learn/css/css_layout/flexbox/index.html new file mode 100644 index 0000000000..72f5d57cf8 --- /dev/null +++ b/files/ko/learn/css/css_layout/flexbox/index.html @@ -0,0 +1,340 @@ +--- +title: Flexbox +slug: Learn/CSS/CSS_layout/Flexbox +tags: + - 문서 + - 안내서 + - 용어집 + - 초보자 + - 코딩스크립팅 + - 학습 +translation_of: Learn/CSS/CSS_layout/Flexbox +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/CSS/CSS_layout/Normal_Flow", "Learn/CSS/CSS_layout/Grids", "Learn/CSS/CSS_layout")}}</div> + +<p class="summary">flexbox는 행과 열 형태로 항목 무리를 배치하는 일차원 레이아웃 메서드입니다. 항목은 부족한 공간에 맞추기 위해 축소되거나 여분의 공간을 채우기 위해 변형된다. 이 문서는 근간이 되는 내용 전체를 설명합니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">선결 사항:</th> + <td>HTML의 기초 (<a href="/ko/docs/Learn/HTML/Introduction_to_HTML">HTML 입문서</a>)와 CSS 작동 방식에 대한 개념(<a href="/en-US/docs/Learn/CSS/Introduction_to_CSS">CSS 입문서</a>를 공부하세요.)</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>웹 레이아웃을 생성하기 위해 flexbox 레이아웃 시스템을 사용하는 방법을 학습하기.</td> + </tr> + </tbody> +</table> + +<h2 id="왜_flexbox인가">왜 flexbox인가?</h2> + +<p>오랫동안 CSS 레이아웃을 작성할 수 있는 신뢰할 수 있는 크로스 브라우저 호환 도구는 <a href="/en-US/docs/Learn/CSS/CSS_layout/Floats">부동체</a> 및 <a href="/en-US/docs/Learn/CSS/CSS_layout/위치잡기">위치잡기</a> 도구였습니다. 이것들은 무난하고 작동하지만, 어떤 면에서는 되려 제한적이고 좌절감을 맞보게 합니다.</p> + +<p>다음과 같은 간단한 레이아웃 요구 사항은 그러한 도구를 사용하여 달성하기가 어렵거나 불가능합니다. 또한, 편리하지도 유연한 방식도 못됩니다.</p> + +<ul> + <li>부모 요소 내부에 포함된 블록 콘텐츠를 세로로 중심부에 맞추기.</li> + <li>사용 가능한 너비와 높이에 관계없이 하나의 컨테이너에 포함된 모든 자녀 요소가 주어진 너비와 높이를 똑같은 크기로 점유하기.</li> + <li>다단 레이아웃에 포함된 모든 단이 서로 다른 크기의 콘텐츠를 포함하고 있더라도 동일한 높이로 채택하기.</li> +</ul> + +<p>다음 섹션에서 확인하겠지만, flexbox는 많은 레이아웃 작업을 훨씬 쉽게 만들어 줍니다. 본격적으로 파헤쳐봅시다!</p> + +<h2 id="간단한_예제_소개">간단한 예제 소개</h2> + +<p>이 문서에서 우리는 여러분이 flexbox의 작동 방식을 이해하는데 도움이 되는 일련의 연습을 수행하도록 하겠습니다. 시작하려면, 첫 번째 착수 파일인 <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/flexbox/flexbox0.html">flexbox0.html</a>을 우리의 깃허브 저장소에서 사본을 내려받기하여 최신 브라우저(Firefox 또는 Chrome 등)에서 동 파일을 열어 코드 편집기에서 코드를 살펴봐야 합니다. 당신은 그걸 시연한 실제 장면을 <a href="http://mdn.github.io/learning-area/css/css-layout/flexbox/flexbox0.html">여기서도</a> 볼 수 있습니다.</p> + +<p>(편집기로 본) 소스안에 최상위 수준에 {{htmlelement("header")}} 요소와 세 개의 {{htmlelement("article")}}를 포함한 {{htmlelement("section")}} 요소가 있음을 알 수 있습니다. 우리는 이것들을 사용해 상당히 표준적인 삼단 레이아웃을 생성할 겁니다.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13406/flexbox-example1.png" style="border-style: solid; border-width: 1px; display: block; height: 324px; margin: 0px auto; width: 800px;"></p> + +<h2 id="flexbox로_레이아웃할_요소_지정">flexbox로 레이아웃할 요소 지정</h2> + +<p>먼저 어떤 요소들을 flexbox로 레이아웃할 요소를 선택해야 합니다. 이를 위해 영향을 주고 싶은 요소의 부모 요소에 특별한 {{cssxref("display")}} 속성값을 지정합니다. 이 경우 우리는 {{htmlelement("article")}} 요소를 레이아웃하길 원하므로 (flex container가 될) {{htmlelement("section")}}에 해당 속성값을 지정합니다:</p> + +<pre class="brush: css">section { + display: flex; +}</pre> + +<p>그 결과는 다음과 같아야 합니다:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13408/flexbox-example2.png" style="border-style: solid; border-width: 1px; display: block; height: 348px; margin: 0px auto; width: 800px;"></p> + +<p>자. 이 단일 선언이 우리에게 필요한 모든 것을 제공합니다. 놀랍죠, 그쵸? 우리는 단의 크기가 동일한 다단 레이아웃를 갖게 되었고, 단의 높이가 모두 같습니다. 이렇게 된 까닭은 (flex container의 자식인) flex item에 주어진 기본값이 이와 같은 일반적인 문제를 해결하도록 설정되었기 때문입니다. 관련 내용은 나중에 추가합니다.</p> + +<div class="note"> +<p><strong>참고</strong>: 인라인 항목을 flexbox로 취급해 레이아웃하길 희망한다면 {{cssxref("display")}} 속성값을 <code>inline-flex</code>로 지정할 수도 있습니다.</p> +</div> + +<h2 id="flex_모델의_측방">flex 모델의 측방</h2> + +<p>요소들을 flexbox로 레이아웃될 때 그 상자들은 두 개의 축을 따라 배치됩니다.</p> + +<p><img alt="flex_terms.png" class="default internal" src="/files/3739/flex_terms.png" style="display: block; margin: 0px auto;"></p> + +<ul> + <li><ruby><strong>기본 축</strong><rp> (</rp><rt>main axis</rt><rp>) </rp></ruby>은 flex item이 배치되고 있는 방향으로 진행하는 축입니다(예: 페이지를 가로지르는 행 또는 페이지 밑으로 쌓이는 열). 이 기본 축의 시작과 끝을 일컬어 <strong>main start</strong>과 <strong>main end</strong>라고 합니다.</li> + <li><ruby><strong>교차축</strong><rp> (</rp><rt>cross axis</rt><rp>) </rp></ruby>은 flex item이 내부에 배치되는 방향에 직각을 이루는 축입니다. 이 축의 시작과 끝을 일컬어 <strong>cross start</strong>과 <strong>cross end</strong>라고 합니다.</li> + <li><code>display: flex</code>이 설정된 부모 요소(우리 예제에서 {{htmlelement("section")}}이 해당)를 일컬어 <ruby><strong>flex container</strong><rp> (</rp><rt>flex container</rt><rp>) </rp></ruby>라고 합니다.</li> + <li>flex container 내부에 flexbox로 레이아웃되는 항목을 일컬어 <ruby><strong>flex item</strong><rp> (</rp><rt>flex items</rt><rp>) </rp></ruby>이라고 합니다(우리 예제에서 {{htmlelement("article")}} 요소가 해당됩니다).</li> +</ul> + +<p>후속 절을 진행할 때 이러한 용어를 명심하길 바랍니다. 사용 중인 어떤 용어에 대해 혼란스러워지면 언제든지 다시 참조할 수 있습니다.</p> + +<h2 id="행_또는_열">행 또는 열?</h2> + +<p>flexbox는 기본 축이 진행되는 방향(자식 flexbox들이 컨테이너 내부에 배치되는 방향)을 지정하는 {{cssxref("flex-direction")}} 속성을 제공합니다. 기본값으로 이것은 <code>row</code>로 설정되어 브라우저의 기본 언어가 작동하는 방향(영어 브라우저의 경우 왼쪽에서 오른쪽)을 따라 일렬로 배치됩니다.</p> + +<p>다음 선언문을 {{htmlelement("section")}} 규칙에 추가하세요:</p> + +<pre class="brush: css">flex-direction: column;</pre> + +<p>이로써 항목 무리를 열 레이아웃으로 되돌려 놓는걸 확인하게 된다. 해당 항목들은 어떤 내용의 CSS를 추가하기 이전 상황과 유사하다. 진도를 더 나가기 전에 동 선언문을 예제에서 삭제하십시오.</p> + +<div class="note"> +<p><strong>참고</strong>: 당신은 <code>row-reverse</code>와 <code>column-reverse</code> 속성값을 사용하여 역방향으로 배치할 수 있습니다. 이들 값으로도 실험해보십시요!</p> +</div> + +<h2 id="접기">접기</h2> + +<p>당신의 레이아웃에 너비 또는 높이가 고정 크기를 갖고 있어 생기는 한 가지 문제는 결국 flexbox 자식 요소가 컨테이너에서 대열이탈하면서 레이아웃이 깨진다는 것입니다. 우리가 제시하는 <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/flexbox/flexbox-wrap0.html">flexbox-wrap0.html</a> 예제를 확인하고 난 뒤 <a href="http://mdn.github.io/learning-area/css/css-layout/flexbox/flexbox-wrap0.html">라이브 보기</a>를 시도하세요(이 예제를 따라해보고 싶다면 이제 이 파일의 사본을 내려받으세요):</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13410/flexbox-example3.png" style="display: block; height: 646px; margin: 0px auto; width: 800px;"></p> + +<p>여기서 우리는 자식들이 정말로 소속 컨테이너에서 이탈하는 모습을 확인할 수 있습니다. 이것을 해소할 수 있는 한 가지 방법은 다음 선언을 {{htmlelement("section")}} 규칙 부분에 추가하면 됩니다:</p> + +<pre class="brush: css">flex-wrap: wrap;</pre> + +<p>또한, 디음 선언문을 {{htmlelement("article")}} 규칙 부분에 추가해보세요:</p> + +<pre class="brush: css">flex: 200px;</pre> + +<p>지금 시도해보십시오. 동 규칙이 포함된 상태에선 레이아웃 모양이 개선되는 걸 보게 됩겁니다:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13412/flexbox-example4.png" style="display: block; height: 646px; margin: 0px auto; width: 800px;">우리는 이제 여러 행을 갖게 되었다. 많은 flexbox 자녀들이 합당하다 싶게 각 행마다 (분배되어) 알맞게 맞춰졌습니다. 대열이탈된 것들은 다음 행으로 넘어갑니다. 아티클 요소에 <code>flex: 200px</code> 선언이 지정되었다는 의미는 각 요소에 적어도 200px 너비가 지정되었다는 의미이다. 우리는 나중에 이 속성에 대해 더 자세히 논의할 겁니다. 마지막 행에 있는 마지막 몇몇 자식들의 각 너비가 더 연장되면서 전체 행이 마찬가지로 채워진 것을 볼 수 있습니다.</p> + +<p>하지만 할 수 있는 게 더 있습니다. 우선, {{cssxref("flex-direction")}} 속성값을 <code>row-reverse</code>로 변경해 보십시오. 이제 여러 행 레이아웃을 보유한 것은 마찬가지지만, 브라우저 창의 반대쪽 구석에서 시작하여 역방향 대열이 된 것이 확인될 겁니다.</p> + +<h2 id="flex-flow_약칭">flex-flow 약칭</h2> + +<p>이 시점에서 {{cssxref("flex-direction")}}와 {{cssxref("flex-wrap")}} — {{cssxref("flex-flow")}}를 대신하는 약칭이 존재한다는 점을 언급할 가치가 있다. 예를 들어, 여러분은 다음을</p> + +<pre class="brush: css">flex-direction: row; +flex-wrap: wrap;</pre> + +<p>다음으로 대체할 수 있다.</p> + +<pre class="brush: css">flex-flow: row wrap;</pre> + +<h2 id="flex_item의_flex_크기_조정">flex item의 flex 크기 조정</h2> + +<p>이제 첫 번째 예제로 복귀해서, 우리가 어떻게 flex item의 비율을 조절할 수 있는지 살펴봅시다. <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/flexbox/flexbox0.html">flexbox0.html</a>사본을 브라우저 탭으로 열거나 <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/flexbox/flexbox1.html">flexbox1.html</a> 사본을 새로운 출발점으로 삼으세요.(<a href="http://mdn.github.io/learning-area/css/css-layout/flexbox/flexbox1.html">라이브 참조</a>).</p> + +<p>첫째, 당신의 CSS 파일 하단에 다음 규칙을 추가하십시오:</p> + +<pre class="brush: css">article { + flex: 1; +}</pre> + +<p>이것은 각 flex item이 기본 축을 따라 남은 공간을 어느 정도나 점유할지를 결정하는 단위가 없는 비율 값입니다. 이 경우, 우리는 각각의 {{htmlelement("article")}} 요소에 1의 값을 부여하고 있는데, 이는 패딩과 여백이 지정된 이후 남은 여분의 공간을 모두 동등한 크기로 점유하게 된다는 의미입니다. 그것은 비율이며, 각 flex item에 400000의 값을 부여하면 정확히 동일한 효과가 있음을 의미합니다.</p> + +<p>이제 이전 규칙 아래에 다음 규칙을 추가합시다.</p> + +<pre class="brush: css">article:nth-of-type(3) { + flex: 2; +}</pre> + +<p>이제 새로 고침할 때, 세 번째 {{htmlelement("article")}}이 다른 두 개보다 사용 가능한 너비의 두 배나 많이 점유한다는 것을 알 수 있습니다. 말하자면 현재 총 4개의 비례 단위가 있는 겁니다. 처음 두 개의 flex item은 각각 하나로 구분되어 사용 가능한 공간의 1/4을 차지합니다. 세 번째 것은 두 개의 단위(2배율)를 차지하기 때문에 사용 가능한 공간의 2/4를 점유합니다(또는 1/2).</p> + +<p>또한 flex 값 내에서 최소 크기 값을 지정할 수 있습니다. 다음과 같이 문서 부분의 기존 규칙을 업데이트해 보십시오.</p> + +<pre class="brush: css">article { + flex: 1 200px; +} + +article:nth-of-type(3) { + flex: 2 200px; +}</pre> + +<p>이것은 기본적으로 "각 flex item은 먼저 사용 가능한 공간에서 200px를 부여받습니다. 그 후, 나머지 사용 가능한 공간은 비례 단위에 따라 분배됩니다." 새로 고침을 해보면 공간 배분 방식이 달라진 것이 확인될 겁니다.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13406/flexbox-example1.png" style="border-style: solid; border-width: 1px; display: block; height: 324px; margin: 0px auto; width: 800px;"></p> + +<p>flexbox의 실제 값은 flex성/반응성에 포함되어 있다고 볼 수 있습니다. 다시말해 브라우저 창의 크기를 재조정하거나 다른 {{htmlelement("article")}} 요소를 추가하더라도 레이아웃이 계속 정상적으로 작동합니다.</p> + +<h2 id="flex_약칭_對_정식_명칭">flex: 약칭 對 정식 명칭</h2> + +<p>{{cssxref("flex")}} 최대 세 가지 서로 다른 값을 지정할 수 있는 약칭 속성입니다.</p> + +<ul> + <li>단위없는 비례 값은 우리가 위에서 논의한 바 있습니다. 단위없는 비례 값은 {{cssxref("flex-grow")}}라는 정식 명칭 속성을 사용하여 개별적으로 지정할 수 있습니다.</li> + <li>두 번째 단위없는 비례 값인 {{cssxref("flex-shrink")}}는 flex item이 컨테이너에서 넘칠때(대열이탈) 존재를 드러냅니다. 이 값은 컨테이너 대열이탈을 방지하기 위해 넘치는 양을 각 flex item의 크기에서 어느 정도나 뺏어올지를 지정합니다. 이 값은 꽤 고수준의 flexbox 기능이며, 우리는 이 문서에서는 추가 내용을 다루지 않겠습니다.</li> + <li>위에서 논의했던 최소 크기 값입니다. 최소 크기 값은 {{cssxref("flex-basis")}}라는 정식 명칭 값을 사용하여 개별적으로 지정될 수 있습니다.</li> +</ul> + +<p>우리는 꼭 사용해야 할 경우가 아니라면(예를 들어, 이전 설정을 재정의하는 등) flex 속성에 정식 명칭을 사용하지 말라고 권고합니다. 정식 명칭의 사용은 추가 코드 작성이 많아 질뿐만 아니라 다소 혼란스러울 수도 있습니다.</p> + +<h2 id="수평_및_수직_정렬">수평 및 수직 정렬</h2> + +<p>또한 flexbox 기능을 사용하여 기본 축 또는 교차축을 따라 flex item을 정렬할수 있습니다. 이 기능은 새로운 예제인 <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/flexbox/flex-align0.html">flex-align0.html</a>을 통해 살펴보자(<a href="http://mdn.github.io/learning-area/css/css-layout/flexbox/flex-align0.html">라이브로도 보세요</a>). flexbox가 우리는 깔끔한 flex형 단추/툴바로 바뀌게될 겁니다. 지금 당장은 몇몇 단추들이 왼쪽 상단 모서리에 몰린 상태의 수평 메뉴 표시줄이 보입니다.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13414/flexbox-example5.png" style="display: block; height: 77px; margin: 0px auto; width: 600px;"></p> + +<p>우선 이 예제의 사본을 취득합니다.</p> + +<p>이제 예제의 CSS의 맨 아래에 다음 내용을 추가하세요:</p> + +<pre class="brush: css">div { + display: flex; + align-items: center; + justify-content: space-around; +}</pre> + +<p>페이지를 새로 고치면 단추가 수평 및 수직으로 중심이 잘 맞춰져 있음을 알 수 있습니다. 우리는 두 가지 새로운 속성을 통해 이 작업을 수행했습니다.</p> + +<p>{{cssxref("align-items")}} 속성은 flex item이 교차축 어디에 놓일 지를 제어합니다.</p> + +<ul> + <li>이 속성값은 기본값으로 <code>stretch</code>입니다. 이 값은 교차축 방향으로 부모 요소를 채우기 위해 모든 flex item을 연장합니다. 부모가 교차 축 방향으로 고정폭이 주어지지 않았다면 모든 flex item이 최장 항목만큼 길어집니다. 이런 방식으로 우리의 첫 번째 예제가 기본값으로 같은 높이의 열을 얻게 된 것입니다.</li> + <li>우리가 위의 코드에서 사용한 <code>center</code> 값은 항목 무리가 자기들 고유의 면적를 유지하는 동시에 교차축을 따라 중심에 놓이게 만듭니다. 그런 까닭에 현재 예제 속 단추가 수직으로 중심에 놓여있습니다.</li> + <li>또한 교차축의 시작과 끝에 맞춰 모든 항목을 정렬하게 해주는 <code>flex-start</code>와 <code>flex-end</code>와 같은 값도 가질 수 있습니다. 자세한 내용은 {{cssxref("align-items")}}을 참조하십시오.</li> +</ul> + +<p>{{cssxref("align-self")}} 속성을 단추에 적용함으로써 flex item에 속한 개별 항목에 대한 {{cssxref("align-items")}}동작을 재지정할 수 있습니다. 예를 들어 다음을 CSS에 추가해보세요:</p> + +<pre class="brush: css">button:first-child { + align-self: flex-end; +}</pre> + +<p>이것이 어떤 효과를 미치는지 한번 보고, 다 보았다면 다시 제거하세요.</p> + +<p>{{cssxref("justify-content")}}는 flex item 무리가 기본 축 상 어디에 놓이는지를 제어합니다.</p> + +<ul> + <li>기본값은 <code>flex-start</code>이며, 이는 모든 항목이 기본 축의 시작 부분에 놓이도록 만듭니다.</li> + <li>당신은 <code>flex-end</code>를 사용하여 항목 무리를 기본 축의 가장자리에 놓이도록 만들 수도 있습니다.</li> + <li><code>center</code>는 <code>justify-content</code>를 대체할 수 있는 값으로 flex item 무리를 기본 축의 중심에 놓이도록 만들겁니다.</li> + <li>우리가 위에서 사용했던 값인 <code>space-around</code>는 유용합니다. 모든 항목을 기본 축을 따라 고르게 분배하고 양쪽 끝에 약간의 공간도 남겨 놓습니다.</li> + <li>그 외에도 <code>space-between</code>이라는 값도 있습니다. 이는 <code>space-around</code>와 매우 흡사하다. 다만 이것은 양쪽 끝에 공간을 남기지 않습니다.</li> +</ul> + +<p>우리는 진도를 더 나가기 전에 여러분이 이들 값을 가지고 어떻게 작동하는지 시험해보라고 권장하고 싶습니다.</p> + +<h2 id="flex_item_순서_정하기">flex item 순서 정하기</h2> + +<p>flexbox에는 소스 순서에 영향을 미치지 않고 flex item의 레이아웃 순서를 변경하는 기능도 있습니다. 이는 전통적인 레이아웃 메서드로는 불가능했던 내용입니다.</p> + +<p>이를 위한 코드는 간단합니다: 당신의 단추표시줄 예제 코도에 다음과 같은 CSS를 추가해 보십시요:</p> + +<pre class="brush: css">button:first-child { + order: 1; +}</pre> + +<p>페이지를 새로 고치면 이제 "스마일" 단추가 기본 축의 끝으로 이동한 것이 확인될 겁니다. 어떻게 이런 식으로 작동하는지 좀 더 상세히 얘기해 보겠습니다:</p> + +<ul> + <li>기본값으로 모든 flex item들은 {{cssxref("order")}} 값이 0입니다.</li> + <li>순위값이 높은 flex item들은 디스플레이 순서상 순위값이 낮은 항목들보다 나중에 나타납니다.</li> + <li>순위값이 동일한 항목들은 소스 순서대로 나타납니다. 따라서 4개 항목의 순서값이 각기 2, 1, 1, 0로 설정된 경우 표시 순서는 제4, 제2, 제3, 제1 순이 됩니다.</li> + <li>제 3항목은 동일한 순서값을 가지고 있지만, 소스 순서 상 제 2항목 뒤에 있기 때문에 제 2 항목 뒤에 나타납니다.</li> +</ul> + +<p>당신은 0 지정 항목보다 일찍 항목을 표시하도록 음수 순서 값을 설정할 수 있습니다. 예를 들어, 다음 규칙을 사용하여 "Blush" 단추를 기본 축의 시작 부분에 표시할 수 있습니다:</p> + +<pre class="brush: css">button:last-child { + order: -1; +}</pre> + +<h2 id="중첩된_flexbox_box">중첩된 flexbox box</h2> + +<p>flexbox를 사용하여 꽤 복잡한 레이아웃을 만들 수 있습니다. flex item을 flex container로 설정해도 전혀 문제없습니다. 그렇게 되면 그 컨테이너의 자녀가 flexbox처럼 배치됩니다. <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/flexbox/complex-flexbox.html">complex-flexbox.html</a>를 찾아보세요. (<a href="http://mdn.github.io/learning-area/css/css-layout/flexbox/complex-flexbox.html">라이브로도 보세요</a>).</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13418/flexbox-example7.png" style="border-style: solid; border-width: 1px; display: block; margin: 0px auto;"></p> + +<p>이를 위한 HTML은 상당히 간단합니다. 세 개의 {{htmlelement("article")}}를 포함하는 {{htmlelement("section")}} 요소가 있습니다. 세 번째 {{htmlelement("article")}}은 세 개의 {{htmlelement("div")}}를 포함하고 있습니다. :</p> + +<pre>section - article + article + article - div - button + div button + div button + button + button</pre> + +<p>앞의 레이아웃에 사용했던 코드를 살펴봅시다.</p> + +<p>먼저 {{htmlelement("section")}}의 자식들을 flexbox로 취급해 배치하였습니다.</p> + +<pre class="brush: css">section { + display: flex; +}</pre> + +<p>다음으로 {{htmlelement("article")}} 무리 자체에 대해 약간의 flex 값을 설정하였습니다. 여기서 두 번째 규칙에 주목하십시오. 우리는 세 번째 {{htmlelement("article")}}이 자기 자식들을 flex item처럼 배치하도록 설정하고 있습니다. 그러나 이번에는 열처럼 배치하고 있습니다.</p> + +<pre class="brush: css">article { + flex: 1 200px; +} + +article:nth-of-type(3) { + flex: 3 200px; + display: flex; + flex-flow: column; +} +</pre> + +<p>다음으로 첫 번째 {{htmlelement("div")}}를 선택합니다. 우리는 먼저 선택된 요소에 100px의 최소 높이를 효과적으로 주기 위해 <code>flex:1 100px;</code>을 사용합니다. 그리고 나서 우리는 그것의 자식들을 ({{htmlelement("button")}} 요소 무리를) flex item처럼 배치하도록 설정했습니다. 여기서 우리는 그것들을 줄 바꿈 행에 배치하고, 우리가 앞서 본 개별 단추 예제에서 했던 것처럼 사용 가능한 공간의 중심에 정렬합니다.</p> + +<pre class="brush: css">article:nth-of-type(3) div:first-child { + flex:1 100px; + display: flex; + flex-flow: row wrap; + align-items: center; + justify-content: space-around; +}</pre> + +<p>마지막으로, 우리는 단추에 약간의 크기를 설정하되, 다소 흥미롭게도 1 auto라는 flex 값을 부여합니다. 이것은 매우 흥미로운 효과를 지니게 되는데, 브라우저 창의 폭을 조정해 보면 확인됩니다. 단추는 최대한의 공간을 점유할 뿐만아니라 동일 선상에 가능한 한 많은 요소를 놓으려고 합니다. 그러나 해당 요소들이 더 이상 동일 선상에 안착할 수 없을 경우 새로운 라인으로 밀려납니다.</p> + +<pre class="brush: css">button { + flex: 1 auto; + margin: 5px; + font-size: 18px; + line-height: 1.5; +}</pre> + +<h2 id="크로스_브라우저_호환성">크로스 브라우저 호환성</h2> + +<p>flexbox 지원은 파이어폭스, 크롬, 오페라, 마이크로소프트 에지 및 인터넷 익스플로러 11, 안드로이드 및 iOS 최신 버전 등 대부분의 신형 브라우저에서 사용할 수 있습니다. 그러나 flexbox를 지원하지 않는 (또는 지원하지만, 실제로 구식 버전의 flexbox를 지원하는) 구형 브라우저 사용자가 여전히 존재한다는 것을 알아야 합니다.</p> + +<p>여러분이 단지 기술을 익히고 실험할 뿐이라면 호환성 문제는 그다지 중요하지 않습니다; 그러나 만약 여러분이 실제 웹사이트에서 flexbox의 사용을 고려하고 있다면, 여러분은 (구형 브라우저에서) 테스트를 수행해야 하고, 최대한 다양한 브라우저 사용자들이 수용할만한 사이트 방문 경험을 보장할 필요가 있습니다.</p> + +<p>flexbox는 몇몇 CSS 기능보다 다소 까다롭습니다. 예를 들어 브라우저에 CSS 그림자 기능이 빠진 경우 해당 사이트을 여전히 사용할 수 있습니다. 그러나 flexbox 기능을 지원하지 않을 경우 레이아웃이 완전히 깨져서 사용할 수 없게 됩니다.</p> + +<p><a href="/ko/docs/Learn/Tools_and_testing/Cross_browser_testing">크로스 브라우저 테스트</a> 단원에서 크로스 브라우저 지원 문제를 극복하기 위한 전략에 대해 논의합니다.</p> + +<h2 id="요약정리">요약정리</h2> + +<p>이로써 flexbox의 기본 안내서를 마감합니다. 재미있는 경험이었기 바라며, 당신이 학습 진도를 더해 갈수록 flexbox를 자유자제로 다룰 수 있게 될 겁니다. 다음으로 CSS 레이아웃의 또 다른 중요한 측면인 CSS grid를 살펴볼 것입니다.</p> + +<div>{{PreviousMenuNext("Learn/CSS/CSS_layout/Normal_Flow", "Learn/CSS/CSS_layout/Grids", "Learn/CSS/CSS_layout")}}</div> + +<div> +<h2 id="이번_단위에는">이번 단위에는</h2> + +<ul> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Introduction">CSS 레이아웃 소개</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/일반_흐름">일반 대열</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Flexbox">flexbox</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Grids">grid</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Floats">부동체</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/위치잡기">위치잡기</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Multiple-column_Layout">다단 레이아웃</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/반응형_디자인">반응형 디자인</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/미디어_쿼리_초보자_안내서">미디어 쿼리 초보자 안내서</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/레거시_조판_메서드">레거시 레이아웃 메서드</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/%EC%9D%B4%EC%A0%84_%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80_%EC%A7%80%EC%9B%90">이전 브라우저 지원</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Fundamental_Layout_Comprehension">레이아웃 이해도 필수 평가</a></li> +</ul> +</div> diff --git a/files/ko/learn/css/css_layout/floats/index.html b/files/ko/learn/css/css_layout/floats/index.html new file mode 100644 index 0000000000..0ee594b2eb --- /dev/null +++ b/files/ko/learn/css/css_layout/floats/index.html @@ -0,0 +1,517 @@ +--- +title: Floats +slug: Learn/CSS/CSS_layout/Floats +tags: + - 다단 + - 안내서 + - 정리 + - 초보자 + - 코딩스크립팅 +translation_of: Learn/CSS/CSS_layout/Floats +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/CSS/CSS_layout/Grids", "Learn/CSS/CSS_layout/Positioning", "Learn/CSS/CSS_layout")}}</div> + +<p class="summary">원래 텍스트 블록 내에서 float 이미지를 위한 {{cssxref("float")}} 속성은 웹 페이지에서 다단 레이아웃을 생성할 용도로 가장 널리 사용되는 도구 중 하나로 자리매김했었습니다. flexbox와 grid의 출현과 함께 float 속성은 이 문서에서 설명하겠지만, 원래의 목적대로 돌아갔습니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">선결 사항:</th> + <td>HTML의 기초 (<a href="/ko/docs/Learn/HTML/Introduction_to_HTML">HTML 입문서</a>)와 CSS 작동 방식에 대한 개념(<a href="/en-US/docs/Learn/CSS/Introduction_to_CSS">CSS 입문서</a>를 공부하세요.)</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>웹페이지상에 float 기능을 생성하는 방법과 clear 속성과 floats clearing 을 배웁니다.</td> + </tr> + </tbody> +</table> + +<h2 id="floats의_배경">floats의 배경</h2> + +<p>float 속성은 웹 개발자가 텍스트 열 내부에 float하는 이미지를 포함하고, 아울러 해당 이미지의 좌측 우측 주변으로 텍스트를 둘러싸는 간단한 레이아웃을 구현할 수 있도록 도입되었습니다. 이런 것은 신문 레이아웃에서 볼 수 있는 종류입니다.</p> + +<p>그러나 웹 개발자들은 이미지뿐만 아니라 무엇이든 float할 수 있음을 빠르게 깨달았고, 그래서 floats 사용이 확대되었습니다. 앞서 살펴본 <a href="/en-US/docs/Learn/CSS/Introduction_to_CSS/Pseudo-classes_and_pseudo-elements#Active_learning_A_fancy_paragraph">고급 단락 예제</a>는 재미있는 드롭캡 효과를 생성하는 데 floats를 어떻게 사용할 수 있는지를 보여줍니다.</p> + +<p>floats는 일반적으로 상대 요소와 나란히 놓이도록 float(浮動)하는 다단 정보를 갖춘 웹 사이트의 전체 레이아웃을 만들는데 널리 사용되어 왔다(기본 행동은 다단 무리가 소스에서 보이는 순서와 같은 순서대로 상대 요소 아래에 자리잡기하는 것이다). 더 새롭고 더 나은 레이아웃 기술이 나와있으므로 이러한 방식으로 floats를 사용하는 것은 <a href="/en-US/docs/Learn/CSS/CSS_layout/Legacy_Layout_Methods">낡은 기술</a>로 간주되어야 합니다.</p> + +<p>이 문서에서는 floats의 적절한 용도에 집중할 것입니다.</p> + +<h2 id="간단한_float_예제">간단한 float 예제</h2> + +<p>floats를 어떻게 사용하는지 알아보자. 우리는 요소 주위에 텍스트 블록을 float하는 것이 포함된 아주 간단한 예제로 시작할 것입니다. 아래 내용을 따라하려면 당신의 컴퓨터에 <code>index.html</code> 파일을 새로 작성하여, 거기에 <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/getting-started/index.html">간단한 HTML 템플릿</a>으로 채우고, 파일 내부의 적절한 위치에 아래 코드를 삽입하면 됩니다. 해당 섹션의 맨 아래에는 최종 코드가 어떻게 생겼는지에 대한 실제 예제가 있습니다.</p> + +<p>첫째, 간단한 HTML로 시작하겠습니다. HTML body 부분에 다음 내용을 추가하고, body 안에 있었던 모든 내용을 제거합니다.</p> + +<pre class="brush: html"><h1>간단한 float 예제</h1> + +<div class="box">float</div> + +<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. </p> + +<p>Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p> + +<p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed est. Nam id risus quis ante semper consectetur eget aliquam lorem. Vivamus tristique elit dolor, sed pretium metus suscipit vel. Mauris ultricies lectus sed lobortis finibus. Vivamus eu urna eget velit cursus viverra quis vestibulum sem. Aliquam tincidunt eget purus in interdum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p></pre> + +<p>이제 다음 CSS를 HTML에 적용하십시요.({{htmlelement("style")}} 요소를 사용할지 개별 <code>.css</code> 파일에 대한 {{htmlelement("link")}}를 사용할지는 당신의 선택 여하에 달려있습니다.):</p> + +<pre class="brush: css">body { + width: 90%; + max-width: 900px; + margin: 0 auto; + font: .9em/1.2 Arial, Helvetica, sans-serif +} + +.box { + width: 150px; + height: 100px; + border-radius: 5px; + background-color: rgb(207,232,220); + padding: 1em; +}</pre> + +<p>지금 저장하고 새로 고침하면, 여러분이 기대한 것과 비슷한 것을 보게 될 것입니다. 다시말해 일반 대열에 속한 상자는 텍스트 위에 위치를 잡고 있습니다. 텍스트가 상자 주변에 float하려면 아래에서 보듯 <code>.box</code> 규칙에 두 가지 속성을 추가하십시요.</p> + +<pre class="brush: css">.box { + float: left; + margin-right: 15px; + width: 150px; + height: 100px; + border-radius: 5px; + background-color: rgb(207,232,220); + padding: 1em; +}</pre> + +<p>이제 저장하고 새로 고침하면 다음과 같은 것을 볼 수 있습니다.</p> + +<div id="부동_1"> +<div class="hidden"> +<h6 id="float_예제_1">float 예제 1</h6> + +<pre class="brush: html"><h1>간단한 float 예제</h1> + +<div class="box">float</div> + +<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. </p> + +<p>Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p> + +<p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed est. Nam id risus quis ante semper consectetur eget aliquam lorem. Vivamus tristique elit dolor, sed pretium metus suscipit vel. Mauris ultricies lectus sed lobortis finibus. Vivamus eu urna eget velit cursus viverra quis vestibulum sem. Aliquam tincidunt eget purus in interdum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p> +</pre> + +<pre class="brush: css">body { + width: 90%; + max-width: 900px; + margin: 0 auto; + font: .9em/1.2 Arial, Helvetica, sans-serif +} + +.box { + float: left; + margin-right: 15px; + width: 150px; + height: 150px; + border-radius: 5px; + background-color: rgb(207,232,220); + padding: 1em; +} +</pre> +</div> +</div> + +<p>{{ EmbedLiveSample('float_1', '100%', 500) }}</p> + +<p>이제 floats가 어떻게 작동하는지 생각해 봅시다. floats로 설정된 대상 요소(이 경우 {{htmlelement("div")}} 요소)는 문서의 일반 레이아웃 대열에서 들어내어 부모 콘테이너(이 경우는 {{htmlelement("body")}})의 왼편에 고정되어 있습니다. 일반 레이아웃 대열에서 float 요소 아래에 오는 모든 콘텐츠는 이제 그 주변을 감싸게 되며, 애초 해당 float 요소가 있던 상층부를 포함해 오른쪽으로 공간을 차지합니다. 거기서 멈추게 됩니다.</p> + +<p>콘텐츠를 오른쪽으로 float하는 것은 정확히 같은 효과를 가져 오지만, float 요소는 역으로 오른쪽에 고정되고 컨텐츠는 float 요소의 왼쪽 주변을 둘러싸게 됩니다. 직전 CSS 규칙 집합에서 float 값을 <code>right</code>로 변경하고 {{cssxref("margin-right")}}를 {{cssxref("margin-left")}}로 대체해 그 결과가 무엇인지 확인하십시오.</p> + +<p>텍스트를 밀어내도록 float에 여백을 추가할 수 있지만, float 로부터 텍스트를 이동시키기 위해 텍스트에 여백을 추가할 수는 없습니다. 왜 그런가하면 float 요소가 일반 대열에서 이탈된 상태이고, 후속 항목에 속한 상자 무리가 실제로 동 float 의 뒤에 나열되기 때문입니다. 당신의 예제에 일부 내용을 변경해보면 그점을 증명할 수 있습니다.</p> + +<p>float 상자의 바로 뒤에 있는 텍스트 형태의 첫 번째 단락에 <code>special</code> 클래스를 추가하십시요. 그 다음에 당신의 CSS에 다음 규칙을 추가합니다. 이들 규칙에 따라 당신의 후속 단락에는 배경색이 주어집니다.</p> + +<pre class="brush: css">.special { + background-color: rgb(79,185,227); + padding: 10px; + color: #fff; +} +</pre> + +<p>해당 효과를 쉽게 확인해보려면 float에 대한 <code>margin-right</code>를 <code>margin</code>으로 대체하여 float의 주변 전체에 공간을 확보하십시오. 아래 예제에서와 같이 단락의 배경이 float 상자 바로 아래에서 펼쳐지는 것을 확인할 수 있습니다.</p> + +<div id="부동_2"> +<div class="hidden"> +<h6 id="float_예제_2">float 예제 2</h6> + +<pre class="brush: html"><h1>간단한 float 예제</h1> + +<div class="box">float</div> + +<p class="special">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. </p> + +<p>Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p> + +<p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed est. Nam id risus quis ante semper consectetur eget aliquam lorem. Vivamus tristique elit dolor, sed pretium metus suscipit vel. Mauris ultricies lectus sed lobortis finibus. Vivamus eu urna eget velit cursus viverra quis vestibulum sem. Aliquam tincidunt eget purus in interdum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p> </pre> + +<pre class="brush: css">body { + width: 90%; + max-width: 900px; + margin: 0 auto; + font: .9em/1.2 Arial, Helvetica, sans-serif +} + +.box { + float: left; + margin: 15px; + width: 150px; + height: 150px; + border-radius: 5px; + background-color: rgb(207,232,220); + padding: 1em; +} + +.special { + background-color: rgb(79,185,227); + padding: 10px; + color: #fff; +} +</pre> +</div> +</div> + +<p>{{ EmbedLiveSample('float_2', '100%', 500) }}</p> + +<p>우리의 후속 요소에 속한 라인 상자가 짧아져서 텍스트가 floats 주위로 펼쳐지고 있지만, floats가 일반 대열에서 제거되었기 때문에 단락 주변 상자는 여전히 전체 너비로 유지하고 있습니다.</p> + +<h2 id="floats_정리하기">floats 정리하기</h2> + +<p>우리는 float가 일반 대열에서 제거되고 다른 요소가 그 옆에 표시되는 것을 보았습니다. 따라서 후속 요소가 치고 올라오는 것을 막으려면 그것을 정리해야 합니다. 그것은 {{cssxref("clear")}} 속성으로 달성됩니다.</p> + +<p>이전 예제에서 당신이 사용한 HTML에서 float 항목 아래에 위치한 두 번째 단락에 <code>cleared</code> 클래스를 추가하십시요. 그 뒤 당신의 CSS에 다음 내용을 추가하세요.</p> + +<pre class="brush: css">.cleared { + clear: left; +} +</pre> + +<div id="부동_3"> +<div class="hidden"> +<h6 id="float_예제_3">float 예제 3</h6> + +<pre class="brush: html"><h1>간단한 float 예제</h1> + +<div class="box">float</div> + +<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. </p> + +<p class="cleared">Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p> + +<p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed est. Nam id risus quis ante semper consectetur eget aliquam lorem. Vivamus tristique elit dolor, sed pretium metus suscipit vel. Mauris ultricies lectus sed lobortis finibus. Vivamus eu urna eget velit cursus viverra quis vestibulum sem. Aliquam tincidunt eget purus in interdum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p> + </pre> + +<pre class="brush: css">body { + width: 90%; + max-width: 900px; + margin: 0 auto; + font: .9em/1.2 Arial, Helvetica, sans-serif +} + +.box { + float: left; + margin: 15px; + width: 150px; + height: 150px; + border-radius: 5px; + background-color: rgb(207,232,220); + padding: 1em; +} + +.cleared { + clear: left; +} +</pre> +</div> +</div> + +<p>{{ EmbedLiveSample('float_3', '100%', 600) }}</p> + +<p>다음 단락은 float 요소를 clear 하며, 더 이상 그 옆에 부상하지 않음을 알아야 합니다. <code>clear</code> 속성은 다음과 같은 값을 받아들입니다:</p> + +<ul> + <li><code>left</code>: 왼쪽에 부상한 항목들 clear</li> + <li><code>right</code>: 오른쪽에 부상한 항목들 clear</li> + <li><code>both</code>: 왼쪽 오른쪽 관계 없이 부상한 항목들 clear</li> +</ul> + +<h2 id="floats_주변을_둘러싼_상자_정리하기">floats 주변을 둘러싼 상자 정리하기</h2> + +<p>이제 당신은 float 요소를 후속하는 무언가를 정리하는 방법을 알고 있지만, 장신 floats와 단신 단락이 있고 두 요소 주변을 둘러싼 하나의 상자가 있을 경우에는 어떤 일이 일어나는지 살펴보십시요. 첫 단락과 우리의 float 상자가 <code>wrapper</code> 클래스에 해당하는 {{htmlelement("div")}} 요소로 둘러싸지도록 문서를 변경하십시오.</p> + +<pre class="brush: html"><div class="wrapper"> + <div class="box">float</div> + + <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate.</p> +</div> +</pre> + +<p>당신의 CSS에 <code>.wrapper</code> 클래스에 대해 다음 규칙을 추가한 뒤 페이지를 새로 고침하십시오.</p> + +<pre class="brush: css">.wrapper { + background-color: rgb(79,185,227); + padding: 10px; + color: #fff; +}</pre> + +<p>원형 <code>.cleared</code> 클래스에 추가된 것입니다.</p> + +<pre class="brush: css" id="ct-0">.cleared { + clear: left; +}</pre> + +<p>여러분이 보게 될 것은 문단에 배경 이미지를 놓는 예제에서와 비슷하게 배경색이 floats 뒤에서 펼쳐지고 있습니다.</p> + +<div id="부동_4"> +<div class="hidden"> +<h6 id="float_예제_4">float 예제 4</h6> + +<pre class="brush: html"><h1>간단한 float 예제</h1> +<div class="wrapper"> + <div class="box">float</div> + + <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. </p> +</div> + +<p class="cleared">Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p> + +<p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed est. Nam id risus quis ante semper consectetur eget aliquam lorem. Vivamus tristique elit dolor, sed pretium metus suscipit vel. Mauris ultricies lectus sed lobortis finibus. Vivamus eu urna eget velit cursus viverra quis vestibulum sem. Aliquam tincidunt eget purus in interdum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p> </pre> + +<pre class="brush: css">body { + width: 90%; + max-width: 900px; + margin: 0 auto; + font: .9em/1.2 Arial, Helvetica, sans-serif +} + +.wrapper { + background-color: rgb(79,185,227); + padding: 10px; + color: #fff; +} + +.box { + float: left; + margin: 15px; + width: 150px; + height: 150px; + border-radius: 5px; + background-color: rgb(207,232,220); + padding: 1em; +} + +.cleared { + clear: left; +} +</pre> +</div> +</div> + +<p>{{ EmbedLiveSample('float_4', '100%', 600) }}</p> + +<p>반복되는 얘기지만, 이렇게 된 까닭은 floats가 정상 대열에서 제거되었기 때문입니다. 후속 요소를 정리해도 이럴 때는 상자 정리 문제에 도움이 되지 않습니다. 즉 상자의 밑단이 float 항목을 애워싸고, 짧은 컨텐츠라도 동 컨텐츠를 애워싸길 원할 경우에는 도움이 되질 않습니다. 이를 처리하려면 생각할 수 있는 세 가지 방법이 있는데, 그 중 두 가지 방법은 모든 브라우저에서 작동하지만, 약간 땜질식이며, 세 번째 새로운 방법은 이런 상황을 제대로 처리합니다.</p> + +<h3 id="The_clearfix_hack">The clearfix hack</h3> + +<p>이 상황을 처리하는 전통적인 방법은 "clearfix hack"이라고 알려진 내용을 사용하는 것입니다. 여기에는 floats와 그걸 둘러싼 콘텐츠가 들어 있는 상자 뒤에 일부 생성된 콘텐츠를 삽입하고, 그것에 (좌측 우측 관계없는) <code>clear: both;</code>를 설정하는 것을 말합니다.</p> + +<p>우리의 예제에 다음과 같은 CSS를 추가하세요.</p> + +<pre class="brush: css">.wrapper::after { + content: ""; + clear: both; + display: block; +}</pre> + +<p>이제 페이지를 새로고침하면 상자가 지워집니다. 이것은 본질적으로 항목 아래에 <code><div></code>와 같은 HTML 요소를 추가하고, 거기에 <code>clear: both</code>를 설정한 것과 같습니다.</p> + +<div id="부동_5"> +<div class="hidden"> +<h6 id="float_예제_5">float 예제 5</h6> + +<pre class="brush: html"><h1>간단한 float 예제</h1> +<div class="wrapper"> + <div class="box">float</div> + + <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. </p> +</div> +<p class="cleared">Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p> + +<p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed est. Nam id risus quis ante semper consectetur eget aliquam lorem. Vivamus tristique elit dolor, sed pretium metus suscipit vel. Mauris ultricies lectus sed lobortis finibus. Vivamus eu urna eget velit cursus viverra quis vestibulum sem. Aliquam tincidunt eget purus in interdum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p> </pre> + +<pre class="brush: css">body { + width: 90%; + max-width: 900px; + margin: 0 auto; + font: .9em/1.2 Arial, Helvetica, sans-serif +} + +.wrapper { + background-color: rgb(79,185,227); + padding: 10px; + color: #fff; +} + +.box { + float: left; + margin: 15px; + width: 150px; + height: 150px; + border-radius: 5px; + background-color: rgb(207,232,220); + padding: 1em; +} + +.wrapper::after { + content: ""; + clear: both; + display: block; +} +</pre> +</div> +</div> + +<p>{{ EmbedLiveSample('float_5', '100%', 600) }}</p> + +<h3 id="overflow_사용">overflow 사용</h3> + +<p>다른 대안으로는 <code>.wrapper</code> 클래스에 {{cssxref("overflow")}} 속성을 <code>visible</code> 이 외의 값으로 설정하는 방법이 있습니다.</p> + +<p>이전 섹션에서 추가한 clearfix CSS 부분을 제거하고 그 대신 <code>.wrapper</code> 클래스에 대한 CSS 규칙에 <code>overflow: auto</code>를 추가합니다. 반복되는 얘기지만, 상자가 정리되었을 겁니다.</p> + +<pre class="brush: css">.wrapper { + background-color: rgb(79,185,227); + padding: 10px; + color: #fff; + overflow: auto; +}</pre> + +<div id="부동_6"> +<div class="hidden"> +<h6 id="float_예제_6">float 예제 6</h6> + +<pre class="brush: html"><h1>간단한 float 예제</h1> +<div class="wrapper"> + <div class="box">float</div> + + <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. </p> +</div> +<p class="cleared">Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p> + +<p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed est. Nam id risus quis ante semper consectetur eget aliquam lorem. Vivamus tristique elit dolor, sed pretium metus suscipit vel. Mauris ultricies lectus sed lobortis finibus. Vivamus eu urna eget velit cursus viverra quis vestibulum sem. Aliquam tincidunt eget purus in interdum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p> </pre> + +<pre class="brush: css">body { + width: 90%; + max-width: 900px; + margin: 0 auto; + font: .9em/1.2 Arial, Helvetica, sans-serif +} + +.wrapper { + background-color: rgb(79,185,227); + padding: 10px; + color: #fff; + overflow: auto; +} + +.box { + float: left; + margin: 15px; + width: 150px; + height: 150px; + border-radius: 5px; + background-color: rgb(207,232,220); + padding: 1em; +} +</pre> +</div> +</div> + +<p>{{ EmbedLiveSample('float_6', '100%', 600) }}</p> + +<p>이 예는 <strong>block formatting context</strong>라고(블록 서식 상황) 알려진 것을 생성하여 처리합니다. 이것은 당신의 페이제 내부 미니 레이아웃과도 같습니다. 그 안에 모든 것이 포함되어 있으므로 우리의 float 요소는 블록 서식 상황 내부에 포함되어 있으며 배경은 두 개 항목 뒤에 펼쳐집니다. 그러나 어떤 경우에는 overflow 사용에 따른 의도하지 않은 결과 때문에 원치 않는 스크롤 막대나 잘린 그림자가 발견될 수 있습니다.</p> + +<h3 id="display_flow-root">display: flow-root</h3> + +<p>이 문제를 해결하는 현대적인 방식은 <code>display</code> 속성에서 <code>flow-root</code>값을 사용하는 방법입니다. 이것은 임시방편을 사용하지 않고 블록 서식 상황을 생성하기 위해만 존재합니다. 이를 사용할 때 의도하지 않은 결과는 없습니다. 당신의 <code>.wrapper</code> 규칙에서 <code>overflow: auto</code>를 제거하고 <code>display: flow-root</code>를 추가합니다. 당신이 이 기능을 지원하는 브라우저가 있다는 가정 하에 상자가 정리될 것입니다.</p> + +<pre class="brush: css">.wrapper { + background-color: rgb(79,185,227); + padding: 10px; + color: #fff; + display: flow-root; +}</pre> + +<div id="부동_7"> +<div class="hidden"> +<h6 id="float_예제_7">float 예제 7</h6> + +<pre class="brush: html"><h1>간단한 float 예제</h1> +<div class="wrapper"> + <div class="box">float</div> + + <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. </p> +</div> +<p class="cleared">Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p> + +<p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed est. Nam id risus quis ante semper consectetur eget aliquam lorem. Vivamus tristique elit dolor, sed pretium metus suscipit vel. Mauris ultricies lectus sed lobortis finibus. Vivamus eu urna eget velit cursus viverra quis vestibulum sem. Aliquam tincidunt eget purus in interdum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p> </pre> + +<pre class="brush: css">body { + width: 90%; + max-width: 900px; + margin: 0 auto; + font: .9em/1.2 Arial, Helvetica, sans-serif +} + +.wrapper { + background-color: rgb(79,185,227); + padding: 10px; + color: #fff; + display: flow-root; +} + +.box { + float: left; + margin: 15px; + width: 150px; + height: 150px; + border-radius: 5px; + background-color: rgb(207,232,220); + padding: 1em; +} +</pre> +</div> +</div> + +<p>{{ EmbedLiveSample('float_7', '100%', 600) }}</p> + +<h2 id="요약정리">요약정리</h2> + +<p>당신은 현대적인 웹 개발에서 floats에 대해 알아야 할 것은 이제 모두 알게 되었습니다. 과거에 어떤 식으로 사용되었는지에 관한 정보에 대해선 <a href="/en-US/docs/Learn/CSS/CSS_layout/Legacy_Layout_Methods">레거시 레이아웃 메서드</a>에 관한 문서를 보십시요. 오래된 프로젝드에 몸 담을 일이 생긴다면 유용할 수도 있습니다.</p> + +<p>{{PreviousMenuNext("Learn/CSS/CSS_layout/Grids", "Learn/CSS/CSS_layout/Positioning", "Learn/CSS/CSS_layout")}}</p> + +<h2 id="이번_단위에는">이번 단위에는</h2> + +<ul> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Introduction">CSS 레이아웃 소개</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/일반_흐름">일반 대열</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Flexbox">flexbox</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Grids">grid</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Floats">floats</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/위치잡기">위치잡기</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Multiple-column_Layout">다단 레이아웃</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/반응형_디자인">반응형 디자인</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/미디어_쿼리_초보자_안내서">미디어 쿼리 초보자 안내서</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/레거시_조판_메서드">레거시 레이아웃 메서드</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/%EC%9D%B4%EC%A0%84_%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80_%EC%A7%80%EC%9B%90">이전 브라우저 지원</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Fundamental_Layout_Comprehension">레이아웃 이해도 필수 평가</a></li> +</ul> diff --git a/files/ko/learn/css/css_layout/grids/index.html b/files/ko/learn/css/css_layout/grids/index.html new file mode 100644 index 0000000000..6e4b7403f5 --- /dev/null +++ b/files/ko/learn/css/css_layout/grids/index.html @@ -0,0 +1,711 @@ +--- +title: 그리드 +slug: Learn/CSS/CSS_layout/Grids +tags: + - 그리드 + - 그리드 레이아웃 + - 씨에스에스 + - 아티클 + - 안내서 + - 자습서 + - 초보자 + - 코딩스크립팅 + - 학습 +translation_of: Learn/CSS/CSS_layout/Grids +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/CSS/CSS_layout/Flexbox", "Learn/CSS/CSS_layout/Floats", "Learn/CSS/CSS_layout")}}</div> + +<p class="summary">CSS 그리드 레이아웃은 웹페이지를 위한 이차원 레이아웃 시스템입니다. 이 기능을 통해 콘텐츠를 행과 열에 배치할 수 있으며 복잡한 레이아웃을 직접 직관적으로 구축할 수 있는 많은 기능이 있습니다. 이 글은 페이지 레이아웃을 시작하기 위해 필요한 모든 것을 알려드립니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">선결 사항:</th> + <td>HTML 기본 (<a href="/ko/docs/Learn/HTML/Introduction_to_HTML">HTML 입문</a> 학습), CSS의 작동 방식 <a href="/ko/docs/Learn/CSS/Introduction_to_CSS">CSS 입문 </a> 및 (<a href="/ko/docs/Learn/CSS/Styling_boxes">박스 양식 지정</a> 학습)</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>그리드 레이아웃 시스템의 근간 개념과 그리드 레이아웃 구현 방법 이해하기</td> + </tr> + </tbody> +</table> + +<h2 id="그리드_레이아웃이란_무엇인가">그리드 레이아웃이란 무엇인가?</h2> + +<p>그리드는 수평선과 수직선으로 이루어진 집합체로, 디자인 요소를 정렬할 수 있는 대상 패턴을 생성한다. 이 디자인은 페이지에서 페이지로 이동할 때 요소가 널뛰거나 너비가 바뀌지 않는 디자인 생성에 도움을 주어 웹 사이트의 일관성을 높여준다.</p> + +<p>하나의 그리드은 대게 <strong>columns</strong>, <strong>rows</strong>로 구성되며, 각 행과 열 사이에 공백이 있는데, 대게는 이를 일컬어 <strong>gutters</strong>라고 부른다.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13899/grid.png" style="display: block; height: 553px; margin: 0px auto; width: 1196px;"></p> + +<h2 id="CSS에서_그리드_생성하기">CSS에서 그리드 생성하기</h2> + +<p>당신의 디자인에 필요한 그리드를 결정했다면 해당 CSS 그리드 레이아웃을 생성하고 그 위에 항목을 올려놓기 위해 CSS 그리드 레이아웃을 사용할 수 있습니다. 우리는 먼저 그리드 레이아웃의 기본 기능을 살펴보고 난 뒤 당신의 프로젝트에 맞는 간단한 그리드 시스템을 생성하는 방법을 살펴보겠습니다.</p> + +<h3 id="그리드의_정의">그리드의 정의</h3> + +<p>본격적인 출발에 앞서 텍스트 편집기 및 브라우저 상에서 <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/grids/0-starting-point.html">시작 파일</a>을 다운로드하고 엽니다(<a href="https://mdn.github.io/learning-area/css/css-layout/grids/0-starting-point.html">여기에서 라이브로 볼 수도 있습니다</a>). 예를 들어, 당신은 일부 자식 항목이 있는 컨테이너 예제를 보게됩니다. 기본값으로 이들은 일반 대열로 표시되므로 상자들은 다른 대상 요소 바로 밑에 표시됩니다. 우리는 이 단원의 첫 번째 부분은 이 (시작) 파일을 가지고 작업할 것이며, 거기에 변경을 더해 그리드가 어떻게 동작하는지 확인하게 됩니다.</p> + +<p>{{cssxref("display")}} 속성에 <code>grid</code> 값을 사용해 그리드를 규정한다. 이로써 Flexbox와 마찬가지로 그리드 레이아웃으로 전환하며, 컨테이너의 직계 자식 전체가 그리드 아이템이 됩니다. 내려받은 시작 파일 내부 CSS 부분에 다음을 추가하세요:</p> + +<pre class="brush: css">.container { + display: grid; +}</pre> + +<p>가변상자와 달리 항목 무리는 즉각적으로 모양이 달리지지 않는다. <code>display: grid</code> 선언으로 열 그리드 하나가 당신에게 주어지며, 따라서 당신의 항목들은 일반 대열 속 행동 방식처럼 다른 대상 요소 바로 밑에 계속 표시된다.</p> + +<p>그리드 같은 모양세를 확인하려면 그리드에 몇 개의 열을 추가할 필요가 있다. 여기에 200픽셀 칼럼 3개를 추가해봅시다. 길이 단위나 백분율을 사용하여 그러한 열 트랙을 만들 수 있습니다.</p> + +<pre class="brush: css">.container { + display: grid; + grid-template-columns: 200px 200px 200px; +}</pre> + +<p>CSS 규칙에 제2 선언을 추가한 다음 페이지를 다시 로드하면 생성된 그리드의 각 셀 안으로 그리드 항목 무리가 하나씩 재배열되는 것이 확인될 것이다.</p> + +<div id="격자_1"> +<div class="hidden"> +<h6 id="간단한_그리드_예제">간단한 그리드 예제</h6> + +<pre class="brush: css">body { + width: 90%; + max-width: 900px; + margin: 2em auto; + font: .9em/1.2 Arial, Helvetica, sans-serif; +} + +.container > div { + border-radius: 5px; + padding: 10px; + background-color: rgb(207,232,220); + border: 2px solid rgb(79,185,227); +} </pre> + +<pre class="brush: html"><div class="container"> + <div>하나</div> + <div>둘</div> + <div>셋</div> + <div>넷</div> + <div>다덧</div> + <div>여섯</div> + <div>일곱</div> +</div> </pre> + +<pre class="brush: css">.container { + display: grid; + grid-template-columns: 200px 200px 200px; +} </pre> +</div> +</div> + +<p>{{ EmbedLiveSample('그리드_1', '100%', 400) }}</p> + +<h3 id="fr_단위를_포함한_가변_그리드">fr 단위를 포함한 가변 그리드</h3> + +<p>길이와 백분율을 사용하여 그리드를 생성하는 것 외에도 <strong><code>fr</code></strong> 단위를 사용하여 그리드 행과 열을 가변적으로 조정할 수 있다. 동 단위는 그리드 컨테이너 내부에 사용 가능한 공간에서 한 개의 분할 부분과 같다.</p> + +<p>트랙 목록을 다음과 같이 정의로 변경하여, 세 개의 <code>1fr</code> 트랙을 생성한다.</p> + +<pre class="brush: css">.container { + display: grid; + grid-template-columns: 1fr 1fr 1fr; +}</pre> + +<p>이제 가변 트랙을 보유했다는 것이 확인될 것이다. <code>fr</code> 단위는 공간을 균등하게 분배하므로 예를 들어 다음과 같이 규정을 변경할 경우 트랙에 서로 다른 값을 부여할 수 있다:</p> + +<pre class="brush: css">.container { + display: grid; + grid-template-columns: 2fr 1fr 1fr; +}</pre> + +<p>첫 번째 트랙은 이제 사용 가능한 공간의 2fr을 얻고 다른 두 트랙은 1fr을 얻음으로써 첫 번째 트랙을 더 크게 만듭니다. <code>fr</code> 단위와 고정 길이 트랙을 혼합할 수 있습니다. 이러한 경우 고정 트랙들에 필요한 공간이 제외한 이후에 해당 공간이 다른 트랙에 분배됩니다.</p> + +<div id="격자_2"> +<div class="hidden"> +<h6 id="fr_단위를_포함하는_그리드_예제">fr 단위를 포함하는 그리드 예제</h6> + +<pre class="brush: css">body { + width: 90%; + max-width: 900px; + margin: 2em auto; + font: .9em/1.2 Arial, Helvetica, sans-serif; +} + +.container { + display: grid; + grid-template-columns: 2fr 1fr 1fr; +} + +.container > div { + border-radius: 5px; + padding: 10px; + background-color: rgb(207,232,220); + border: 2px solid rgb(79,185,227); +} + </pre> + +<pre class="brush: html"><div class="container"> + <div>하나</div> + <div>둘</div> + <div>셋</div> + <div>넷</div> + <div>다덧</div> + <div>여섯</div> + <div>Seven</div> +</div> </pre> +</div> +</div> + +<p>{{ EmbedLiveSample('그리드_2', '100%', 400) }}</p> + +<div class="note"> +<p><strong>참고</strong>: <code>fr</code> 단위는 <em>전체</em> 공간이 아닌 <em>이용 가능한</em> 공간을 분배한다. 따라서 당신의 트랙 중 하나가 자기 내부에 뭔가 큰 공간을 차지한다면 공유할 수 있는 여유 공간이 줄어들 것이다.</p> +</div> + +<h3 id="트랙사이_간격">트랙사이 간격</h3> + +<p>우리가 트랙사이 간격을 생성하려면 열 사이 간격에 대해선 {{cssxref("grid-column-gap")}} 속성을 사용하고, 행 사이 간격에 대해선 {{cssxref("grid-row-gap")}}를 사용하고, 단번에 둘 다 설정하려면 {{cssxref("grid-gap")}}를 사용한다.</p> + +<pre class="brush: css">.container { + display: grid; + grid-template-columns: 2fr 1fr 1fr; + grid-gap: 20px; +} +</pre> + +<p>이러한 간격은 길이 단위 또는 백분율이 될 수 있지만, <code>fr</code> 단위는 될 수 없습니다.</p> + +<div id="격자_3"> +<div class="hidden"> +<h6 id="fr_단위를_사용하는_간단한_그리드_예제">fr 단위를 사용하는 간단한 그리드 예제</h6> + +<pre class="brush: css">body { + width: 90%; + max-width: 900px; + margin: 2em auto; + font: .9em/1.2 Arial, Helvetica, sans-serif; +} + +.container { + display: grid; + grid-template-columns: 2fr 1fr 1fr; + grid-gap: 20px; +} + +.container > div { + border-radius: 5px; + padding: 10px; + background-color: rgb(207,232,220); + border: 2px solid rgb(79,185,227); +} + </pre> + +<pre class="brush: html"><div class="container"> + <div>하나</div> + <div>둘</div> + <div>셋</div> + <div>넷</div> + <div>다덧</div> + <div>여섯</div> + <div>일곱</div> +</div> +</pre> +</div> +</div> + +<p>{{ EmbedLiveSample('그리드_3', '100%', 400) }}</p> + +<div class="note"> +<p><strong>참고</strong>: <code>*gap</code> 속성은 예전에는 <code>grid-</code> 접두사를 사용하곤 했지만, 해당 CSS 규격은 변경되었다. 당시는 그들 속성을 여러 레이아웃 메서드 상에서 사용할 수 있게 하자는 취지였다. 현재 마이크로소프트 에지와 파이어폭스는 해당(grid-) 접두사가 없는 버전을 지원하며 접두사 버전은 별칭으로 유지되므로 한동안 사용하는 데 지장이 없을 것이다. 당신이 안전한 쪽을 택하려면 완전 무결한 코드를 담보하기 위해 두 가지 속성을 이중으로 추가할 수 있다.</p> +</div> + +<pre class="brush: css">.container { + display: grid; + grid-template-columns: 2fr 1fr 1fr; + grid-gap: 20px; + gap: 20px; +}</pre> + +<h3 id="트랙_목록의_반복">트랙 목록의 반복</h3> + +<p>반복 표기법을 사용하여 당신의 트랙 목록의 전체 또는 한 섹션을 반복할 수 있다. 트랙 목록을 다음 항목으로 변경하라.</p> + +<pre class="brush: css">.container { + display: grid; + grid-template-columns: repeat(3, 1fr); + grid-gap: 20px; +}</pre> + +<p>이제 당신은 이전과 마찬가지로 3개의 1fr 트랙을 얻을 수 있다. 반복 함수에 전달되는 첫 번째 값은 당신이 원하는 트랙 목록의 반복 횟수가 되며, 두 번째 값은 하나의 트랙 목록이며, 이는 당신이 반복되길 원하는 일개 트랙 또는 여러 트랙이 될 수도 있다.</p> + +<h3 id="암시적_그리드와_명시적_그리드">암시적 그리드와 명시적 그리드</h3> + +<p>지금까지는 열 트랙만 지정했지만, 콘텐츠를 저장하기 위해 행도 만들어지고 있다. 이것은 명시적 그리드 대항 암시적 그리드의 한 예다. 명시적 그리드는 당신이 <code>grid-template-columns</code> 또는 <code>grid-template-rows</code>를 사용하여 생성하는 것을 말한다. 암시적 그리드가 생성되는 시점은 콘텐츠가 해당 그리드 외부에 배치될 때이다. 예를 들어 콘텐츠가 행렬 내부에 진입할 시점이 된다. 명시적 및 암시적 그리드는 가변상자의 주축 및 교차축과 유사하다.</p> + +<p>기본값으로 암시적 그리드 상에 생성된 트랙은 <code>auto</code> 크기로 되며, 이는 일반적으로 콘텐츠를 알맞게 들여놓기에 충분히 크다는 것을 의미한다. 당신이 암시적 그리드 트랙에 크기를 지정하려면 {{cssxref("grid-auto-rows")}}와 {{cssxref("grid-auto-columns")}} 속성을 사용할 수 있다. 당신의 작업 CSS에 <code>100px</code>값을 <code>grid-auto-rows</code>에 추가하게 되면 생성된 행이 이제 100 픽셀 높이가 되는 걸 보게 된다.</p> + +<div id="격자_4"> +<div class="hidden"> +<h6 id="fr_단위를_사용하는_간단한_그리드_예제_2">fr 단위를 사용하는 간단한 그리드 예제</h6> + +<pre class="brush: css">body { + width: 90%; + max-width: 900px; + margin: 2em auto; + font: .9em/1.2 Arial, Helvetica, sans-serif; +} + +.container > div { + border-radius: 5px; + padding: 10px; + background-color: rgb(207,232,220); + border: 2px solid rgb(79,185,227); +} </pre> + +<pre class="brush: html"><div class="container"> + <div>하나</div> + <div>둘</div> + <div>셋</div> + <div>넷</div> + <div>다덧</div> + <div>여섯</div> + <div>일곱</div> +</div> + </pre> +</div> + +<pre class="brush: css">.container { + display: grid; + grid-template-columns: repeat(3, 1fr); + grid-auto-rows: 100px; + grid-gap: 20px; +}</pre> +</div> + +<p>{{ EmbedLiveSample('그리드_4', '100%', 400) }}</p> + +<h3 id="minmax_함수">minmax() 함수</h3> + +<p>100픽셀 높이의 트랙은 100픽셀 이상의 트랙에 콘텐츠를 추가할 경우 별로 유용하지 않을 것이다. 그 경우 오버플로를 야기하니 말이다. <em>적어도</em> 100픽셀 높이의 트랙이 있고, 거기에 더 많은 콘텐츠가 들어가더라도 여전히 확장될 수 있다면 더 나을 수 있다. 웹에 관한 상당히 기본적인 사실은 어떤 것의 높이가 앞으로 얼마나 커질지 결코 모른다는 점이다. 추가 내용 또는 더 큰 글꼴 크기는 모든 면에서 픽셀 크기의 완전성을 추구하는 디자인의 경우 문제를 일으킬 수 있다.</p> + +<p><code>minmax</code>는 트랙의 최소 및 최대 크기를 설정할 수 있게 해준다. 예를 들어 <code>minmax(100px, auto)</code>. 최소 크기는 100 픽셀이지만 최대 크기는 <code>auto</code>로써 콘텐츠에 들어맞게 확장된다. 최소최대값을 사용하려면 <code>grid-auto-rows</code>를 변경해보라.</p> + +<pre class="brush: css">.container { + display: grid; + grid-template-columns: repeat(3, 1fr); + grid-auto-rows: minmax(100px, auto); + grid-gap: 20px; +}</pre> + +<p>추가 콘텐츠를 추가하면 트랙이 확장되어 콘텐츠가 들어맞게 트랙이 확대되는 걸 보게될 겁니다. 정확히 행을 따라 확장이 일어난다는 점에 유의하십시오.</p> + +<h3 id="들어맞을_때까지_열_생성">들어맞을 때까지 열 생성</h3> + +<p>우리는 트랙 목록, 반복 표기법, <code>minmax()</code>등에 대해 우리가 배운 몇 가지를 결합하여 유용한 패턴을 만들 수 있다. 때로는 그리드 컨테이너에 들여놓기할 때 최대한 많은 열을 생성하라고 그리드에 요청할 수 있으면 도움이 된다. 우리는 그렇게 하려면 <code>repeat()</code> 표기법을 사용하여 <code>grid-template-columns</code>의 값을 설정하면 되지만, 숫자로 전달할 게 아니라 키워드 <code>auto-fill</code>을 사용했다. 동 함수의 두 번째 매개 변수의 경우 최소값은 우리가 갖고 싶은 최소 트랙 크기와 같고 최대값은 1fr이다.</p> + +<p>이를 당신의 파일에서 당장 시험해려면 아래 CSS를 사용하십시요:</p> + +<div id="격자_5"> +<div class="hidden"> +<h6 id="들어맞을_때까지_열_생성_2">들어맞을 때까지 열 생성</h6> + +<pre class="brush: css">body { + width: 90%; + max-width: 900px; + margin: 2em auto; + font: .9em/1.2 Arial, Helvetica, sans-serif; +} + +.container > div { + border-radius: 5px; + padding: 10px; + background-color: rgb(207,232,220); + border: 2px solid rgb(79,185,227); +} + </pre> + +<pre class="brush: html"><div class="container"> + <div>하나</div> + <div>둘</div> + <div>셋</div> + <div>넷</div> + <div>다덧</div> + <div>여섯</div> + <div>일곱</div> +</div> </pre> +</div> + +<pre class="brush: css">.container { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); + grid-auto-rows: minmax(100px, auto); + grid-gap: 20px; +}</pre> +</div> + +<p>{{ EmbedLiveSample('그리드_5', '100%', 400) }}</p> + +<p>이것이 작동하는 까닭은 그리드가 그리드 컨테이너에 들어갈 수 있는 200픽셀의 열을 최대한 많이 만들고, 그 뒤 전체 열 사이 남은 공간이 얼마가 돼건 공유하기 때문이다. 최대치 1fr이며, 이미 알고 있듯이 트랙 사이 공간을 고르게 분배한다.</p> + +<h2 id="라인_기반_배치">라인 기반 배치</h2> + +<p>이제 우리는 그리드를 만드는 것에서 그리드에 사물을 배치하는 것으로 넘어간다. 우리의 그리드에는 항상 라인이 있으며, 이 라인은 1에서 시작하며, 문서의 쓰기 모드와 관련이 있다. 따라서 영어에서는 열 라인 1은 그리드의 왼쪽에 위치하고 행 라인 1은 맨 위에 있습니다. 아랍어 열 라인 1은 아랍어가 오른쪽에서 왼쪽으로 쓰여지기 때문에 오른쪽에 놓이게 됩니다.</p> + +<p>시작 라인과 끝 라인을 지정하여 이러한 라인에 따라 사물을 배치할 수 있다. 다음의 속성을 사용하여 그렇게 할 수 있다:</p> + +<ul> + <li>{{cssxref("grid-column-start")}}</li> + <li>{{cssxref("grid-column-end")}}</li> + <li>{{cssxref("grid-row-start")}}</li> + <li>{{cssxref("grid-row-end")}}</li> +</ul> + +<p>이들 속성은 모두 라인 번호를 값으로 가질 수 있습니다. 약칭 속성을 사용할 수도 있습니다.</p> + +<ul> + <li>{{cssxref("grid-column")}}</li> + <li>{{cssxref("grid-row")}}</li> +</ul> + +<p>이를 통해 시작 라인과 끝 라인을 한 번에 지정할 수 있으며, 전진 슬래시인 <code>/</code> 문자로 구분한다.</p> + +<p><a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/grids/8-placement-starting-point.html">착수 파일로 이 파일을 다운로드하세요</a> 또는 <a href="https://mdn.github.io/learning-area/css/css-layout/grids/8-placement-starting-point.html">여기 라이브로도 보세요</a>. 이미 정의된 그리드와 윤곽이 잡힌 간단한 글이 있습니다. 자동 배치에 의해 항목들이 우리가 생성한 그리드 무리의 각 셀에 하나씩 배치하는 것을 볼 수 있습니다.</p> + +<p>대신 그리드 라인을 사용하여 우리 사이트의 모든 요소를 그리드에 배치합니다. 다음 CSS 규칙을 당해 CSS의 맨 아래에 추가세요:</p> + +<pre class="brush: css">header { + grid-column: 1 / 3; + grid-row: 1; +} + +article { + grid-column: 2; + grid-row: 2; +} + +aside { + grid-column: 1; + grid-row: 2; +} + +footer { + grid-column: 1 / 3; + grid-row: 3; +}</pre> + +<div id="격자_6"> +<div class="hidden"> +<h6 id="라인_기반_배치_2">라인 기반 배치</h6> + +<pre class="brush: css"> body { + width: 90%; + max-width: 900px; + margin: 2em auto; + font: .9em/1.2 Arial, Helvetica, sans-serif; + } + + .container { + display: grid; + grid-template-columns: 1fr 3fr; + grid-gap: 20px; + } +header { + grid-column: 1 / 3; + grid-row: 1; +} + +article { + grid-column: 2; + grid-row: 2; +} + +aside { + grid-column: 1; + grid-row: 2; +} + +footer { + grid-column: 1 / 3; + grid-row: 3; +} + +header, +footer { + border-radius: 5px; + padding: 10px; + background-color: rgb(207,232,220); + border: 2px solid rgb(79,185,227); +} + +aside { + border-right: 1px solid #999; +} +</pre> + +<pre class="brush: html"><div class="container"> + <header>이것은 나의 사랑스런 블로그입니다</header> + <article> + <h1>내 글</h1> + <p>Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p> + + <p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed est. Nam id risus quis ante semper consectetur eget aliquam lorem. Vivamus tristique elit dolor, sed pretium metus suscipit vel. Mauris ultricies lectus sed lobortis finibus. Vivamus eu urna eget velit cursus viverra quis vestibulum sem. Aliquam tincidunt eget purus in interdum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p> + </article> + <aside> + <h2>Other things</h2> + <p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed est.</p> + </aside> + <footer>Contact me@mysite.com</footer> +</div> </pre> +</div> +</div> + +<p>{{ EmbedLiveSample('그리드_6', '100%', 400) }}</p> + +<div class="note"> +<p><strong>참고</strong>: 마지막 열 또는 행 라인을 상대로 <code>-1</code> 값을 사용할 수 있으며, 음수값을 사용하여 끝에서 안쪽으로 카운트할 수도 있습니다. 그러나 이 값은 명시적 그리드에만 통합니다. <code>-1</code> 값은 암시적 그리드의 마지막 라인에 적용하지 못합니다.</p> +</div> + +<h2 id="grid-template-areas로_위치잡기">grid-template-areas로 위치잡기</h2> + +<p>그리드에 항목을 배치하는 다른 방식은 {{cssxref("grid-template-areas")}} 속성을 사용하여 당신의 디자인에 딸린 다양한 요소에 이름을 지정하는 것입니다.</p> + +<p>마지막 예제에서 라인 기반 위치잡기를 제거하고(또는 예제 파일을 다시 다운로드하여 새롭게 시작하거나), 다음 CSS를 추가한다.</p> + +<pre class="brush: css">.container { + display: grid; + grid-template-areas: + "header header" + "sidebar content" + "footer footer"; + grid-template-columns: 1fr 3fr; + grid-gap: 20px; +} + +header { + grid-area: header; +} + +article { + grid-area: content; +} + +aside { + grid-area: sidebar; +} + +footer { + grid-area: footer; +}</pre> + +<p>페이지를 새로고침하면, 우리가 어떤 라인 번호를 사용할 필요없이 방금 전과 같이 항목이 배치되었음을 알 수 있습니다!</p> + +<div id="격자_7"> +<div class="hidden"> +<h6 id="라인_기반_배치_3">라인 기반 배치</h6> + +<pre class="brush: css">body { + width: 90%; + max-width: 900px; + margin: 2em auto; + font: .9em/1.2 Arial, Helvetica, sans-serif; +} + +header, +footer { + border-radius: 5px; + padding: 10px; + background-color: rgb(207,232,220); + border: 2px solid rgb(79,185,227); +} + +aside { + border-right: 1px solid #999; +} + +.container { + display: grid; + grid-template-areas: + "header header" + "sidebar content" + "footer footer"; + grid-template-columns: 1fr 3fr; + grid-gap: 20px; +} + +header { + grid-area: header; +} + +article { + grid-area: content; +} + +aside { + grid-area: sidebar; +} + +footer { + grid-area: footer; +} + </pre> + +<pre class="brush: html"><div class="container"> + <header>이것은 나의 사랑스런 블로그입니다</header> + <article> + <h1>내 글</h1> + <p>Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p> + + <p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed est. Nam id risus quis ante semper consectetur eget aliquam lorem. Vivamus tristique elit dolor, sed pretium metus suscipit vel. Mauris ultricies lectus sed lobortis finibus. Vivamus eu urna eget velit cursus viverra quis vestibulum sem. Aliquam tincidunt eget purus in interdum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p> + </article> + <aside><h2>Other things</h2> + <p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed est.</p> + </aside> + <footer>Contact me@mysite.com</footer> +</div> </pre> +</div> +</div> + +<p>{{ EmbedLiveSample('그리드_7', '100%', 400) }}</p> + +<p><code>grid-template-areas</code>에 대한 규칙은 다음과 같다.</p> + +<ul> + <li>그리드로 이뤄진 전체 셀을 채우도록 해야 합니다.</li> + <li>두 개의 셀을 합치려면 해당 이름을 반복하십시오.</li> + <li>셀을 비우려면 <code>.</code>(마침표)를 사용하세요.</li> + <li>영역은 반드시 직사각형이어야 한다. 예를 들어 L자 모양의 면적을 취할 수는 없다.</li> + <li>영역은 다른 위치에서 반복될 수 없습니다.</li> +</ul> + +<p>우리의 레이아웃을 마음대로 부릴 수 있습니다. 예를 들어, 콘텐츠와 사이드바 아래에만 위치하는 바닥글을 맡바닥까지 확대 점유하도록 변경할 수 있다. 이것은 CSS에서 정확히 무슨 일이 일어나고 있는지 있는 그대로 명백하게 레이아웃을 설명하는 매우 멋진 방법입니다.</p> + +<h2 id="CSS_그리드_그리드_프레임워크">CSS 그리드, 그리드 프레임워크</h2> + +<p>그리드 "프레임워크"는 대략 12 또는 16개의 열 그리드를 기반으로 하는 경향이 있으며, CSS 그리드도 포함하므로, 그러한 프레임워크를 발휘하기 위해 제 3의 타사 도구가 필요하지 않다. 이미 CSS 규격에 포함되어 있기 때문이다.</p> + +<p><a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/grids/11-grid-system-starting-point.html">착수 파일을 다운로드하세요.</a>. 여기에는 12개의 열 그리드로 정의된 컨테이너와 이전 두 예제에서 사용된 것과 동일한 마크업이 포함되어 있습니다. 이제 라인 기반 배치를 사용하여 우리의 콘텐츠를 12열 그리드 상에 배치할 수 있습니다.</p> + +<pre class="brush: css">header { + grid-column: 1 / 13; + grid-row: 1; +} + +article { + grid-column: 4 / 13; + grid-row: 2; +} + +aside { + grid-column: 1 / 4; + grid-row: 2; +} + +footer { + grid-column: 1 / 13; + grid-row: 3; +}</pre> + +<div id="격자_8"> +<div class="hidden"> +<h6 id="CSS_그리드_그리드_시스템">CSS_그리드_그리드_시스템</h6> + +<pre class="brush: css">body { + width: 90%; + max-width: 900px; + margin: 2em auto; + font: .9em/1.2 Arial, Helvetica, sans-serif; +} + +.container { + display: grid; + grid-template-columns: repeat(12, minmax(0,1fr)); + grid-gap: 20px; +} + +header { + grid-column: 1 / 13; + grid-row: 1; +} + +article { + grid-column: 4 / 13; + grid-row: 2; +} + +aside { + grid-column: 1 / 4; + grid-row: 2; +} + +footer { + grid-column: 1 / 13; + grid-row: 3; +} + +header, +footer { + border-radius: 5px; + padding: 10px; + background-color: rgb(207,232,220); + border: 2px solid rgb(79,185,227); +} + +aside { + border-right: 1px solid #999; +} + </pre> + +<pre class="brush: html"><div class="container"> + <header>이것은 나의 사랑스런 블로그입니다</header> + <article> + <h1>내 글</h1> + <p>Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p> + + <p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed est. Nam id risus quis ante semper consectetur eget aliquam lorem. Vivamus tristique elit dolor, sed pretium metus suscipit vel. Mauris ultricies lectus sed lobortis finibus. Vivamus eu urna eget velit cursus viverra quis vestibulum sem. Aliquam tincidunt eget purus in interdum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p> + </article> + <aside><h2>Other things</h2> + <p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed est.</p> + </aside> + <footer>Contact me@mysite.com</footer> +</div> + </pre> +</div> +</div> + +<p>{{ EmbedLiveSample('그리드_8', '100%', 400) }}</p> + +<p><a href="/en-US/docs/Tools/Page_Inspector/How_to/Examine_grid_layouts">파이어폭스 그리드 검사기</a>를 사용하여 당신의 디자인 상의 그리드 라인을 겹쳐놓으면 12개로 구성된 열 그리드가 작동하는 방법을 볼 수 있습니다.</p> + +<p><img alt="A 12 column grid overlaid on our design." src="https://mdn.mozillademos.org/files/16045/learn-grids-inspector.png" style="height: 1026px; width: 2028px;"></p> + +<h2 id="요약정리">요약정리</h2> + +<p>이 개요에서 우리는 CSS 그리드 레이아웃의 주요 특징을 둘러 보았습니다. 당신의 디자인 상에 사용할 수 있도록 합시다. CSS 규격에 대해 더 자세히 살펴보려면 그리드 레이아웃에 대한 안내서를 참조하십시오. 아래를 보면 찾아 볼 수 있습니다.</p> + +<h2 id="참조_항목">참조 항목</h2> + +<ul> + <li><a href="/ko/docs/Web/CSS/CSS_Grid_Layout#Guides">CSS_그리드_안내서</a></li> + <li><a href="/ko/docs/Tools/Page_Inspector/How_to/Examine_grid_layouts">CSS 그리드 검사기: 그리드 레이아웃을 검사</a></li> +</ul> + +<p>{{PreviousMenuNext("Learn/CSS/CSS_layout/Flexbox", "Learn/CSS/CSS_layout/Floats", "Learn/CSS/CSS_layout")}}</p> + +<h2 id="이번_단위에는">이번 단위에는</h2> + +<ul> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Introduction">CSS 레이아웃 소개</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/일반_흐름">일반 대열</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Flexbox">가변상자</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Grids">그리드</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Floats">부동체</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/%EC%9C%84%EC%B9%98%EC%9E%A1%EA%B8%B0">위치잡기</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Multiple-column_Layout">다단 레이아웃</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/%EB%B0%98%EC%9D%91%ED%98%95_%EB%94%94%EC%9E%90%EC%9D%B8">반응형 디자인</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/%EB%AF%B8%EB%94%94%EC%96%B4_%EC%BF%BC%EB%A6%AC_%EC%B4%88%EB%B3%B4%EC%9E%90_%EC%95%88%EB%82%B4%EC%84%9C">미디어 쿼리 초보자 안내서</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Legacy_Layout_Methods">레거시 레이아웃 메서드</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/%EC%9D%B4%EC%A0%84_%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80_%EC%A7%80%EC%9B%90">이전 브라우저 지원</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Fundamental_Layout_Comprehension">레이아웃 이해도 필수 평가</a></li> +</ul> diff --git a/files/ko/learn/css/css_layout/index.html b/files/ko/learn/css/css_layout/index.html new file mode 100644 index 0000000000..b184282450 --- /dev/null +++ b/files/ko/learn/css/css_layout/index.html @@ -0,0 +1,76 @@ +--- +title: CSS 레이아웃 +slug: Learn/CSS/CSS_layout +tags: + - 가변상자 + - 격자 + - 다단 + - 단위 + - 부동 + - 부동체 + - 씨에스에스 + - 안내서 + - 위치잡기 + - 조판 + - 초보자 + - 테이블 + - 학습 +translation_of: Learn/CSS/CSS_layout +--- +<div>{{LearnSidebar}}</div> + +<p>이 시점에서 우리는 이미 CSS 기본 사항, 텍스트 스타일링 방법, 콘텐츠가 안에 있는 상자를 스타일링하고 조작하는 방법을 살펴 보았습니다. 이제 뷰포트와 관련하여 상자를 올바른 장소에 배치하는 방법을 살펴볼 때입니다. 우리는 필요한 전제조건을 다루었기 때문에 이제 CSS 레이아웃에 깊이 뛰어들어 다른 디스플레이 설정, 플렉스박스, CSS 그리드, 포지셔닝과 같은 현대적인 레이아웃 도구, 그리고 당신이 여전히 알고 싶어할 만한 레거시 기술들을 살펴볼 수 있다.</p> + +<h2 id="선결사항">선결사항</h2> + +<p>이번 단위를 시작하기 전에 여러분은 이미 아래 내용을 익혔어야 합니다:</p> + +<ol> + <li><a href="/ko/docs/Learn/HTML/Introduction_to_HTML">HTML 소개</a> 단위에서 논의했듯이 HTML에 대해 기본적인 친숙도가 있어야 합니다.</li> + <li><a href="/ko/docs/Learn/CSS/Introduction_to_CSS">CSS 소개</a> 단위에서 논의한 만큼 CSS 기본 사항에 대해 부담이 없어야 합니다.</li> + <li><a href="/en-US/docs/Learn/CSS/Styling_boxes">상자 스타일링</a> 방법에 대한 이해가 있어야 합니다.</li> +</ol> + +<div class="note"> +<p><strong>참고</strong>: 여러분은 본인만의 파일을 생성할 능력이 없는 컴퓨터/태블릿/다른 장치에서 작업하고 있는 경우, <a href="http://jsbin.com/">JSBin</a>나 <a href="https://thimble.mozilla.org/">Thimble</a>과 같은 온라인 코딩 프로그램 상에서 코드 예제를 시험해볼 수 있다.</p> +</div> + +<h2 id="안내서">안내서</h2> + +<p>이 글은 CSS에서 이용할 수 있는 기본 레이아웃 도구 및 기술에 대한 지침을 제공합니다. 단원 말미에 웹페이지 하나를 예시하는 방식으로 레이아웃 매서드에 대한 이해도를 자가 점검하는데 도움이 되는 학습 평가가 있습니다.</p> + +<dl> + <dt><a href="/ko/docs/Learn/CSS/CSS_layout/Introduction">CSS 레이아웃 입문서</a></dt> + <dd>이 문서에서는 이전 모듈에서 이미 다뤘던 CSS 레이아웃 기능, 예를 들어 서로 다른 {{cssxref("display")}} 속성값의 차이 등을 복습하고, 이번 모듈에서 다룰 예정인 몇몇 CSS 개념을 소개합니다.</dd> + <dt><a href="/ko/docs/Learn/CSS/CSS_layout/일반_흐름">일반 대열</a></dt> + <dd>웹페이지의 엘리먼트 무리는 여러분이 무언가 변화를 주기전까지는 <em>normal flow</em>(일반 대열)에 따라 또래 엘리먼트들을 배치합니다. 이 글은 일반 대열을 설명하는데, 그 걸 토대로 일반 대열 자체를 변경하는 방법을 배우겠습니다.</dd> + <dt><a href="/ko/docs/Learn/CSS/CSS_layout/Flexbox">Flexbox</a></dt> + <dd><a href="/ko/docs/Web/CSS/CSS_Flexible_Box_Layout/%EA%B0%80%EB%B3%80%EC%83%81%EC%9E%90%EC%9D%98_%EB%8C%80%ED%91%9C%EC%A0%81%EC%9D%B8_%EC%82%AC%EC%9A%A9%EB%A1%80">Flexbox</a>는 행과 열의 형태로 항목 무리를 배치하는 일차원 레이아웃 메서드이다. 항목은 부족한 공간에 맞추기 위해 축소되거나 여분의 공간을 채우기 위해 변형된다. 이 글은 근간이 되는 내용 전체를 설명한다.</dd> + <dt><a href="/ko/docs/Learn/CSS/CSS_layout/Grids">그리드(Grids)</a></dt> + <dd>CSS 그리드 레이아웃(Grid Layout)은 웹페이지를 위한 이차원 레이아웃 시스템입니다. 이 기능을 통해 콘텐츠를 행과 열에 배치할 수 있으며 복잡한 레이아웃을 직접 직관적으로 구축할 수 있는 많은 기능이 있습니다. 이 글은 페이지 레이아웃을 시작하기 위해 필요한 모든 것을 알려드립니다.</dd> + <dt><a href="/ko/docs/Learn/CSS/CSS_layout/Floats">부동체</a></dt> + <dd>원래 텍스트 블록 내에서 부동 이미지를 위한 {{cssxref("float")}} 속성은 웹 페이지에서 다단 레이아웃을 생성할 용도로 가장 널리 사용되는 도구 중 하나로 자리매김했었습니다. Flexbox와 그리드의 출현과 함께 부동 속성은 이 글에서 설명하겠지만, 원래의 목적대로 돌아갔습니다.</dd> + <dt><a href="/ko/docs/Learn/CSS/CSS_layout/위치잡기">위치잡기</a></dt> + <dd>당신이 일반 문서 레이아웃 대열에서 엘리먼트를 끄집어 내어, 그것이 다르게 행동하게 만들수 있게 해주는 것이 위치잡기다. 예를 들어 상대 엘리먼트 위에 놓거나 브라우저 뷰 포트 내부의 동일한 위치를 항상 유지하게 해준다. 이 글은 서로 다른 {{cssxref("position")}} 값을 설명하고, 그 걸 사용하는 방법에 대해서도 설명한다.</dd> + <dt><a href="/ko/docs/Learn/CSS/CSS_layout/Multiple-column_Layout">다단 레이아웃</a></dt> + <dd>CSS 다단 레이아웃 규격은 신문에서 볼 수 있듯이 콘텐츠를 단으로 배치하는 방법을 제공합니다. 이 글은 그 기능을 어떻게 사용하는지 설명합니다.</dd> + <dt><a href="/ko/docs/Learn/CSS/CSS_layout/%EB%B0%98%EC%9D%91%ED%98%95_%EB%94%94%EC%9E%90%EC%9D%B8">반응형 디자인</a></dt> + <dd>웹 기반 장치에 다양한 화면 크기가 등장함에 따라 반응형 웹 디자인(RWD) 개념이 등장했습니다. 말하자면 서로 다른 화면 너비와 해상도 등에 맞게 웹 페이지가 레이아웃과 모양을 변경할 수 있는 일련의 실례를 집대성한 것입니다. 이 아이디어가 우리가 멀티 디바이스 웹에 대한 설계 방식을 바꾸게 만든 장본인입니다. 이 글에서 우리는 그 내용을 숙달하기 위해 당신이 알아야하는 주요 기술을 이해하도록 도울 것입니다.</dd> + <dt><a href="/ko/docs/Learn/CSS/CSS_layout/미디어_쿼리_초보자_안내서">미디어 쿼리 초보자 안내서</a></dt> + <dd><strong>CSS Media Query</strong>는 예를 들어 "뷰포트가 480 픽셀보다 넓다."라고 여러분이 지정한 규칙에 브라우저 및 장치 환경이 일치하는 경우에만 CSS를 적용할 수 있는 방법을 제공합니다. 미디어 쿼리는 반응형 웹 디자인의 핵심 부분이다. 뷰포트의 크기에 따라 서로 다른 레이아웃을 생성할 수 있기 때문이다. 그러나 예를들면 사용자는 마우스가 아닌 터치스크린을 사용하는지와 같이 실행 중인 사이트 환경에 대한 여러 내용들을 탐지하는 데도 사용할 수 있습니다. 이번 단원에서는 먼저 미디어 쿼리에 사용된 구문에 대해 배우고, 이어 해당 구문을 가공의 예제에서 사용하여 간단한 디자인이 어떻게 반응할 수 있는지 살펴보겠습니다.</dd> + <dt><a href="/ko/docs/Learn/CSS/CSS_layout/Legacy_Layout_Methods">레거시 레이아웃 메서드</a></dt> + <dd>그리드 시스템은 CSS 레이아웃에서 사용되는 매우 일반적인 기능이며, CSS 그리드 레이아웃(Grid Layout) 이전에는 부동체 또는 기타 레이아웃 기능을 이용하여 그리드 레이아웃(Grid Layout)이 구현되는 경향이 있었습니다. 자신의 레이아웃을 정해진 수의 열(예를 들어 4, 6 또는 12열)이라 상상한 뒤 여러분의 콘텐츠를 그 가상의 열 안에 콘텐츠 열을 끼워맞춥니다. 이 글에서 우리는 이 오래된 메서드가 어떻게 작동하는지 탐구할 것입니다. 이는 여러분이 오래된 프로젝트에 몸을 담게 될 경우에 그들 메서드의 사용 방법에 대한 이해를 돕기 위함입니다.</dd> + <dt><a href="/ko/docs/Learn/CSS/CSS_layout/%EC%9D%B4%EC%A0%84_%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80_%EC%A7%80%EC%9B%90">이전 브라우저 지원</a></dt> + <dd> + <p>이 단위에서는 Flexbox 및 그리드를 여러분의 웹디자인을 위한 주 레이아웃 방법으로 사용할 것을 권장합니다. 그러나 이전 브라우저 또는 당신이 사용하는 메서드를 지원하지 않는 브라우저를 사용하는 사이트 방문자가 있습니다. 이런 일은 웹상에서 항상 있는 일입니다. 즉 새로운 기능이 개발됨에 따라 서로 다른 브라우저가 서로 다른 것들의 우선 순위를 정합니다. 이 글은 구식 기술의 사용자들을 차단하지 않고 현대적인 웹 기술을 사용하는 방법에 대해 설명합니다.</p> + </dd> + <dt><a href="/ko/docs/Learn/CSS/CSS_layout/Fundamental_Layout_Comprehension">학습 평가: 레이아웃 이해의 핵심 사항</a></dt> + <dd>웹페이지를 하나 예시하는 방식으로 서로 다른 레이아웃 메서드 지식을 테스트하는 학습 평가</dd> +</dl> + +<h2 id="참조_항목">참조 항목</h2> + +<dl> + <dt><a href="/ko/docs/Learn/CSS/CSS_layout/Practical_positioning_examples">위치잡기 실례</a></dt> + <dd>이 글은 위치잡기로 당신이 할 수 있는 일의 종류를 설명하기 위해 실제 사례를 구축하는 방법을 제시합니다.</dd> +</dl> diff --git a/files/ko/learn/css/css_layout/introduction/index.html b/files/ko/learn/css/css_layout/introduction/index.html new file mode 100644 index 0000000000..aaf42a6979 --- /dev/null +++ b/files/ko/learn/css/css_layout/introduction/index.html @@ -0,0 +1,720 @@ +--- +title: CSS 레이아웃 입문서 +slug: Learn/CSS/CSS_layout/Introduction +tags: + - 가변상자 + - 격자 + - 글 + - 대열 + - 부동체 + - 씨에스에스 + - 위치잡기 + - 입문서 + - 조판 + - 초보용 + - 테이블 + - 학습 +translation_of: Learn/CSS/CSS_layout/Introduction +--- +<div>{{LearnSidebar}}</div> + +<div>{{NextMenu("Learn/CSS/CSS_layout/Normal_Flow", "Learn/CSS/CSS_layout")}}</div> + +<p class="summary">이 문서에서는 이전 모듈에서 이미 다뤘던 CSS 레이아웃 기능, 예를 들어 서로 다른 {{cssxref("display")}} 속성값의 차이 등을 복습하고, 이번 모듈에서 다룰 예정인 몇몇 CSS 개념을 소개합니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">선결 사항:</th> + <td>HTML의 기초 (<a href="/ko/docs/Learn/HTML/Introduction_to_HTML">HTML에 대한 소개</a>)와 CSS 작동 방식에 대한 개념(<a href="/en-US/docs/Learn/CSS/Introduction_to_CSS">CSS 소개</a>를 공부하세요.)</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>CSS 페이지 레이아웃 기술에 대한 개요를 제공합니다. 개별 기술은 후속 자습서에서 보다 자세하게 학습할 수 있습니다.</td> + </tr> + </tbody> +</table> + +<p>CSS 페이지 레이아웃 기술은 웹페이지에 포함될 요소들을 취합할 수 있게 해주며, 그들 요소가 일반 레이아웃 대열 상에 기본값 위치 기준과 부모 컨테이너, 또는 메인 뷰포인트 및 메인창과 비례해 어느 위치에 놓일 것인지를 제어한다. 우리가 이번 모듈에서 자세하게 다룰 페이지 레이아웃 기술은 다음과 같다.</p> + +<ul> + <li>보통 흐름(normal flow)</li> + <li>{{cssxref("display")}} 속성</li> + <li>flexbox</li> + <li>그리드</li> + <li>Floats</li> + <li>포지셔닝</li> + <li>테이블 레이아웃</li> + <li>다단 레이아웃</li> +</ul> + +<p>각각의 기술은 저마다 용도가 있고, 장단점이 있으며, 어떤 기술도 독립적인 용도를 갖추도록 설계되지는 않았다. 각 메서드가 어떤 용도로 마련된 것인지 이해하게 되면 해당 작업에 가장 적합한 도구가 어떤 것인지 파악하는 데 유리한 입지를 점하게 된다.</p> + +<h2 id="보통_흐름normal_flow">보통 흐름(normal flow)</h2> + +<p>보통 흐름(normal flow)은 당신이 페이지 레이아웃을 전혀 제어하지 않을 경우 브라우저가 기본값으로 HTML 페이지를 배치하는 방법을 말합니다. 간단한 HTML 예를 살펴봅시다:</p> + +<pre class="brush: html"><p>나는 고양이를 사랑한다.</p> + +<ul> + <li>고양이 먹이를 사세요</li> + <li>운동</li> + <li>기운내 친구야</li> +</ul> + +<p>여기가 끝!</p></pre> + +<p>기본적으로 브라우저는 이 코드를 다음과 같이 표시한다.</p> + +<p>{{ EmbedLiveSample('일반_대열', '100%', 200) }}</p> + +<p>소스 코드에 나타나는 순서 그대로 HTML 요소가 표시되는 방법에 주의하자. 요소가 상대 요소의 상위(上位)에 차곡 차곡 올려진다. 즉 첫 번째 단락이 나오고 순서가 없는 목록이 이어지고 두 번째 단락으로 이어진다.</p> + +<p>요소 집합이 상대 요소 바로 아래 나타나는 것을 <em>inline</em> 요소와 대비해 <em>block</em> 요소라고 기술한다.</p> + +<div class="note"> +<p><strong>참고</strong>: 블록 요소 상황에 해당하는 방향으로 배치되는 것을 일컽어 블록 방향이라고 기술한다. 영어와 같은 언어 상에서 블록 방향은 수직 대열을 갖게되며, 이는 가로쓰기 모드이다. 일본어와 같은 세로 쓰기 모드에 해당하는 언어 상에서 블록 방향은 수평 대열이 됩니다. (블록 관계와) 대척 관계인 인라인 방향은 (문장과 같은) 인라인 콘텐츠가 흘러가는 방향을 말한다.</p> +</div> + +<p>CSS를 사용하여 레이아웃을 만들 경우 당신은 요소 집합을 보통 흐름(normal flow)에서 벗어나도록 하는 것이다. 그러나 당신의 웹페이지의 다수 요소 집합의 경우는 보통 흐름(normal flow)이므로 정확히 당신이 필요로하는 레이아웃이 그대로 만들어질 것이다. 그런 까닭에 잘 구조화된 HTML 문서에서 시작하는 것이 아주 중요하다. 그런 뒤에 당신은 사물들이 기본값으로 배치된 방식과 대립해 싸우는게 아니라 협력해서 작업할 수 있게 된다.</p> + +<p>CSS에서 요소가 배치되는 방식을 변경시키는 메서드는 다음과 같다.</p> + +<ul> + <li><strong>{{cssxref("display")}} 속성</strong> — <code>block</code>, <code>inline</code> 또는 <code>inline-block</code>과 같은 기준 속성값은 보통 흐름(normal flow)속에서 요소가 동작하는 방식을 변경할 수 있다. (더 자세한 정보는 <a href="/en-US/docs/Learn/CSS/Introduction_to_CSS/Box_model#Types_of_CSS_boxes">CSS 상자 유형</a>을 참조하세요). 그 뒤에 우리에게 <code>display</code> 속성값 지정을 통해 활성화될 수 있는 완전체 레이아웃 메서드가 주어진다. 예로 <a href="/ko/docs/Learn/CSS/CSS_layout/Grids">CSS 그리드</a>와 <a href="/ko/docs/Learn/CSS/CSS_layout/Flexbox">flexbox</a>.</li> + <li><strong>Floats</strong> — {{cssxref("float")}} 속성의 값을 예로 <code>left</code>로 적용하면 흔히 메거진 레이아웃에 속한 이미지가 텍스트를 자신의 주변에 떠있게 하는 방식과 같이 블록 수준 요소가 어떤 요소의 한 쪽 측면으로 밀려나도록 할 수 있다.</li> + <li><strong>{{cssxref("position")}} 속성은</strong> — 다른 상자 내부에 들어가 상자의 정확한 위치를 제어할 수 있게 해준다. <code>정적</code> 포지셔닝는 기본값으로 보통 흐름(normal flow) 소속이지만, 다른 속성값을 사용해 요소들이 다르게 배치되도록 만들 수 있다. 예를 들어 브라우저 뷰포트의 왼쪽 최상단에 맞춰 (또는 비례해서) 위치를 고정시킬 수 있다.</li> + <li><strong>테이블 레이아웃</strong> — 이것은 HTML 테이블 구성원에 스타일을 지정하기 위해 마련된 기능이기는 하나 <code>display: table</code>와 관련 속성을 사용하여 비테이블 요소에서도 사용될 수 있다.</li> + <li><strong>다단 레이아웃</strong> — <a href="/en-US/docs/Web/CSS/CSS_Columns">다단 레이아웃</a> 속성은 당신이 신문 지상에서 볼 수 있듯이 블록 콘텐츠를 단 형태로 배치되도록 만들 수 있다.</li> +</ul> + +<h2 id="디스플레이_속성">디스플레이 속성</h2> + +<p>CSS 상에서 페이지 레이아웃을 완성하는 주요 메서드는 <code>display</code> 속성에 포함된 모든 속성값 지정을 통해 이뤄진다. 디스플레이 속성은 요소가 표시되는 기본값 변경을 허용한다. 보통 흐름(normal flow)상의 모든 요소는 한 가지 <code>display</code> 속성값을 갖고 있으며, 해당 요소의 기본 동작 방식을 지정하는 데 사용된다. 예를 들어 영어로 된 단락은 다른 대상 요소 바로 밑에 표시되는 것은 그들 요소의 스타일이 <code>display: block</code>으로 지정되었기 때문이다. 단락 내부 어떤 텍스트 주변에 링크를 만들면 그 링크는 나머지 텍스트와 함께 인라인을 유지하며 새 줄로 넘어가는 행갈이를 하지 않는다. 그런 까닭에 {{htmlelement("a")}} 요소는 기본값으로 <code>display: inline</code>가 된다.</p> + +<p>당신은 이러한 기본값 디스플레이 동작을 변경할 수 있다. 예를 들어 {{htmlelement("li")}} 요소는 기본값으로 <code>display: block</code>가 지정되는 것으로 우리 영어 문서 상에서 다른 대상 요소 바로 밑에 표시된다는 의미다. 디스플레이 속성값을 <code>inline</code>으로 변경하면 문장 속 단어의 동작과 마찬가지로 상대 바로 옆에 표시된다. 당신이 어느 요소라도 <code>display</code> 속성값을 변경할 수 있다는 것은 그 요소들이 어떤 모습을 띄게되든 관계없이 해당 HTML 요소의 의미론적 의의를 선택할 수 있다는 뜻이다. 요소가 보여지는 방식은 변경할 수 있는 부분이다.</p> + +<p>한 항목을 <code>block</code>에서 <code>inline</code>으로 바꾸거나, 그 반대로 바꿔 기본값진열 방식을 변경할 수 있을뿐만 아니라 하나의 <code>display</code> 속성값으로 시작해서 확대된 형태의 레이아웃 메서드로 일부 있다. 그러나 그것을 사용할 경우 대게는 추가적인 속성 호출이 요구된다. 레이아웃의 목적이 무엇인지 논할 때 가장 중요한 두 가지 속성값은 <code>display: flex</code>와 <code>display: grid</code>이다.</p> + +<h2 id="flexbox">flexbox</h2> + +<p>flexbox는 <a href="/ko/docs/Web/CSS/CSS_Flexible_Box_Layout">가변 상자 레이아웃</a> 모듈의 약칭으로 행이 됐건 열이 됐건 일차원 상에 사물을 배치할 경우 편리를 돕기 위해 마련되었다. flexbox를 사용하려면 당신이 진열하길 원하는 모든 요소의 부모 요소에 <code>display: flex</code>를 적용하고 나면 모든 직계 자식이 플렉스 항목이 된다. 우리는 간단한 예를 들어 이 점을 확인할 수 있다.</p> + +<p>아래 HTML 마크업을 보면<code>wrapper</code> 클래스에 해당하는 컨테이너 요소를 제공하고, 그 내부에 세 개의 {{htmlelement("div")}} 요소가 있다. 기본값으로 이들 요소들은 영어 문서 상에서 블록 요소로 상대 요소 밑에 표시된다.</p> + +<p>그러나 부모 요소에 <code>display: flex</code>를 부여하면 세개 항목이 자체적으로 단으로 배열된다. 그렇게 된 까닭은 그들 요소들이 <em>가변 항목</em>이 되었을 뿐만 아니라 flexbox가 그들 요소에 부여한 일부 초기값을 사용했기 때문이다. 그들은 행으로 표시되었는데, 그 까닭은 {{cssxref("flex-direction")}}의 초기값이 <code>row</code>이기 때문이다. 그들은 모두 항목 무리에서 키가 가장 큰 높이로 연장된 모양새가 되는데, 그 까닭은 {{cssxref("align-items")}} 속성의 초기값이 <code>stretch</code>이기 때문이다. 즉, 항목 무리가 가변 컨테이너의 높이에 맞춰 연장된다는 것으로 이번 경우에 키가 가장 큰 항목이 기준으로 정해진다. 항목 무리 전체가 가변 컨테이너의 초입에 맞춰 정렬하면서 행의 말미에 여분의 공간이 남겨진다.</p> + +<div id="가변_1"> +<div class="hidden"> +<h6 id="flexbox_예제_1">flexbox 예제 1</h6> + +<pre class="brush: css">* {box-sizing: border-box;} + +.wrapper > div { + border-radius: 5px; + background-color: rgb(207,232,220); + padding: 1em; +} + </pre> +</div> + +<pre class="brush: css">.wrapper { + display: flex; +} +</pre> + +<pre class="brush: html"><div class="wrapper"> + <div class="box1">하나</div> + <div class="box2">둘</div> + <div class="box3">셋</div> +</div> +</pre> +</div> + +<p>{{ EmbedLiveSample('가변_1', '300', '200') }}</p> + +<p>가변 콘테이너에 적용될 수 있는 상기한 속성이외에도 가변 항목에 적용될 수 있는 속성이 있다. 다른 것들 중에서 그들 속성들은 항목이 변형되는 방식을 변경할 수 있는데, 항목을 여유 공간에 맞춰 연장하거나 수축될 수 있다.</p> + +<p>이에 대한 간단한 예로 자식 항목 전체에 대한 {{cssxref("flex")}} 속성에 대해 속성값 <code>1</code>을 부가할 수 있다. 그로 인해 컨테이너 말미에 공간을 남기지 않고 항목 무리 전체가 확대되거나 채워지도록 만든다. 항목 무리보다 많은 공간이 있을 경우는 늘어날 것이고 적은 공간이 있으면 축소될 것이다. 게다가 HTML 마크업에 다른 요소를 추가하면 그 대상 요소를 위한 공간 생성을 위해 항목 무리 전체가 축소될 것이다. 그들은 그 요소가 뭐가됐건 동일한 공간 점유를 위해 크기가 조종된다.</p> + +<div id="가변_2"> +<div class="hidden"> +<h6 id="flexbox_예제_2">flexbox 예제 2</h6> + +<pre class="brush: css"> * {box-sizing: border-box;} + + .wrapper > div { + border-radius: 5px; + background-color: rgb(207,232,220); + padding: 1em; + } + </pre> +</div> + +<pre class="brush: css">.wrapper { + display: flex; +} + +.wrapper > div { + flex: 1; +} +</pre> + +<pre class="brush: html"><div class="wrapper"> + <div class="box1">하나</div> + <div class="box2">둘</div> + <div class="box3">셋</div> +</div> +</pre> +</div> + +<p>{{ EmbedLiveSample('가변_2', '300', '200') }}</p> + +<div class="note"> +<p><strong>참고</strong>: 이 안내서는 flexbox 상에서 있을 수 있는 내용에 대한 짧은 입문서였다. 더 자세한 내용은 <a href="/en-US/docs/Learn/CSS/CSS_layout/Flexbox">flexbox</a> 편을 참조하세요.</p> +</div> + +<h2 id="그리드_레이아웃">그리드 레이아웃</h2> + +<p>가변 상자는 일차원 레이아웃을 위해 마련되었지만, 그리드 레이아웃은 이차원 레이아웃을 위해 마련되었다. 즉 행과 열에 포함된 사물들을 배열한다.</p> + +<p>반복되는 얘기지만, 디스플레이 속성에 <code>display: grid</code>라는 특정 값을 지정하면 그리드 레이아웃으로 전환할 수 있다. 아래 예를 보면 가변 요소 사례에 비슷한 마크업을 사용했다. 하나의 컨테이너와 몇몇 자식 요소가 딸려있다. 우리는 <code>display: grid</code> 사용뿐만 아니라 {{cssxref("grid-template-rows")}}와 {{cssxref("grid-template-columns")}}라는 개별 속성을 활용하여 부모 요소를 상대로 일부 행과 열 궤도를 정의한다. 여기 각기 <code>1fr</code>값이 지정된 3열과 <code>100px</code>이 지정된 2행을 정의했다. 자식 요소 상에 굳이 어떤 규칙도 적용할 필요없이, 그 요소들이 우리가 생성한 그리드 안에 자동적으로 자리잡게 된다.</p> + +<div id="격자_1"> +<div class="hidden"> +<h6 id="그리드_예제_1">그리드 예제 1</h6> + +<pre class="brush: css"> * {box-sizing: border-box;} + + .wrapper > div { + border-radius: 5px; + background-color: rgb(207,232,220); + padding: 1em; + } + </pre> +</div> + +<pre class="brush: css">.wrapper { + display: grid; + grid-template-columns: 1fr 1fr 1fr; + grid-template-rows: 100px 100px; + grid-gap: 10px; +} +</pre> + +<pre class="brush: html"><div class="wrapper"> + <div class="box1">하나</div> + <div class="box2">둘</div> + <div class="box3">셋</div> + <div class="box4">넷</div> + <div class="box5">다섯</div> + <div class="box6">여섯</div> +</div> +</pre> +</div> + +<p>{{ EmbedLiveSample('격자_1', '300', '330') }}</p> + +<p>그리드가 주어지고 나면 앞서 확인했듯 당신의 항목 무리를 그리드 상에 자동 배치하는 동작 방식이 아니라 명시적으로 위치를 지정할 수 있다. 아래 두 번째 예제에서 동일한 그리드를 정의했지만, 이번에는 세개의 자식 항목이 주어졌다. 우리는 {{cssxref("grid-column")}}와 {{cssxref("grid-row")}}를 사용해서 각 항목의 행과 열의 시작과 끝을 지정했다. 이로써 항목 무리가 차지하는 공간이 여러 궤도에 걸쳐 확대되었다.</p> + +<div id="격자_2"> +<div class="hidden"> +<h6 id="그리드_예제_2">그리드 예제 2</h6> + +<pre class="brush: css"> * {box-sizing: border-box;} + + .wrapper > div { + border-radius: 5px; + background-color: rgb(207,232,220); + padding: 1em; + } + </pre> +</div> + +<pre class="brush: css">.wrapper { + display: grid; + grid-template-columns: 1fr 1fr 1fr; + grid-template-rows: 100px 100px; + grid-gap: 10px; +} + +.box1 { + grid-column: 2 / 4; + grid-row: 1; +} + +.box2 { + grid-column: 1; + grid-row: 1 / 3; +} + +.box3 { + grid-row: 2; + grid-column: 3; +} +</pre> + +<pre class="brush: html"><div class="wrapper"> + <div class="box1">하나</div> + <div class="box2">둘</div> + <div class="box3">셋</div> +</div> +</pre> +</div> + +<p>{{ EmbedLiveSample('격자_2', '300', '330') }}</p> + +<div class="note"> +<p><strong>참고</strong>: 이 두 예제는 그리드 레이아웃의 일부분일 뿐이며, 자세한 내용은 <a href="/en-US/docs/Learn/CSS/CSS_layout/Grids">그리드 레이아웃</a></p> +</div> + +<p>이 가이드의 나머지 부분은 페이지의 주요 레이아웃 구조로 보기엔 덜 중요하지만 특정 작업을 수행하는 데 여전히 도움이 될 수 있는 다른 레이아웃 방법을 다룬다. 각 레이아웃 작업의 특성을 이해함으로써 당신이 디자인 하는 특정 구성 요소를 들여다 볼 때 거기에 가장 적합한 레이아웃 유형이 종종 명확해 진다는 것을 조만간 알게 될 것이다.</p> + +<h2 id="Floats">Floats</h2> + +<p>요소를 부동시키면 보통 흐름(normal flow)속에 속한 해당 요소와 해당 요소를 뒤따르는 블록 수준 요소의 동작이 변경된다. 요소는 왼쪽 또는 오른쪽으로 이동하고 보통 흐름(normal flow)에서 벗어나게되며 주변 콘텐츠는 부유된 항목 주위로 떠다닙니다.</p> + +<p>이 {{cssxref("float")}} 속성은 네 가지 값을 가질 수 있다:</p> + +<ul> + <li><code>left</code> — 요소를 왼쪽에 띄웁니다.</li> + <li><code>right</code> — 요소를 오른쪽에 띄웁니다.</li> + <li><code>none</code> — 부동 여부를 전혀 지정하지 않는다. 이것이 기본값이다.</li> + <li><code>inherit</code> — 부동 속성의 값이 요소의 부모 요소에서 상속된다고 지정한다.</li> +</ul> + +<p>아래 예제에서 우리는 <code><div></code> 왼쪽을 띄우고 오른쪽에 {{cssxref("margin")}}을 주어 텍스트를 <code><div></code> 요소 자리에서 밀어낸다. 이것은 우리에게 텍스트가 그 상자를 감싸는 효과를 부여하며, 이는 현대 웹 디자인에서 사용되는 Floats에 대해 알아야할 내용의 대부분이다.</p> + +<div id="부동_1"> +<div class="hidden"> +<h6 id="Floats_예제">Floats 예제</h6> + +<pre class="brush: css">body { + width: 90%; + max-width: 900px; + margin: 0 auto; +} + +p { + line-height: 2; + word-spacing: 0.1rem; +} + +.box { + background-color: rgb(207,232,220); + border: 2px solid rgb(79,185,227); + padding: 10px; + border-radius: 5px; +} +</pre> +</div> + +<pre class="brush: html"><h1>간단한 부동 예제</h1> + +<div class="box">부동</div> + +<p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p> + +</pre> + +<pre class="brush: css"> +.box { + float: left; + width: 150px; + height: 150px; + margin-right: 30px; +} +</pre> +</div> + +<p>{{ EmbedLiveSample('부동_1', '100%', 600) }}</p> + +<div class="note"> +<p><strong>참고</strong>: Floats에 대한 설명은 <a href="/en-US/docs/Learn/CSS/CSS_layout/Floats">부동 및 해제</a> 속성 편에서 충분히 다룹니다. flexbox 및 그리드 레이아웃과 같은 기술이 나오기 이전에 Floats는 열 레이아웃을 만드는 메서드로 사용되었다. 웹에서 이러한 메서드와 대면하는 경우도 여전히 있다. <a href="/ko/docs/Learn/CSS/CSS_layout/Legacy_Layout_Methods">레거시 레이아웃 메서드</a>에 관한 단원에서 그 내용을 다루게 된다.</p> +</div> + +<h2 id="포지셔닝_기술">포지셔닝 기술</h2> + +<p>포지셔닝를 통해 보통 흐름(normal flow)속에 있는 요소를 예상되는 기존의 배치 위치에서 벗어나 다른 위치로 이동시킬 수 있다. 포지셔닝는 메인 페이지 레이아웃을 생성하는 메서드가 아니라 페이지의 특정 항목의 위치를 관리하고 미세 조정하는 것에 관한 것이다.</p> + +<p>그러나 {{cssxref("position")}} 속성에 의존하는 특정 레이아웃 패턴을 상대할 경우 유용한 기술도 있다. 포지셔닝를 이해하는 것은 또한 보통 흐름(normal flow)을 이해하고, 항목을 보통 흐름(normal flow)에서 벗어나게 한다는 것이 무엇인지를 이해하는 데 도움이 된다.</p> + +<p>당신이 알아야 할 다섯 가지 포지셔닝 유형이 있다.</p> + +<ul> + <li><strong>정적 포지셔닝</strong>는 모든 요소에 기본값으로 부여된 속성이다. 즉, "문서 레이아웃 대열에 속하는 요소를 기존의 일반 위치에 들여놓는 것으로 여기서 특별할 것은 없다."라는 것을 의미한다.</li> + <li><strong>상대 포지셔닝</strong>페이지상의 요소 위치를 수정하여 그것을 보통 흐름(normal flow)상의 기존 위치와 비례해 이동토록 하는 것으로 페이지의 다른 요소와 겹치는 것도 해당한다.</li> + <li><strong>절대 포지셔닝</strong>는 요소를 페이지의 일반 레이아웃 대열에서 완전히 벗어난 곳으로 이동시켜 자체적인 개별 레이어 상에 놓는 것과 같다. 그곳으로부터 페이지의 <code><html></code> 요소(또는 가장 근접 위치에 있는 조상 요소)의 가장자리 기준에서 비례하는 위치에 고정할 수 있다. 이것은 다른 콘텐츠 패널이 서로 다른 요소 위에 놓여야 하는 동시에 표시 및 감추기를 맘대로 하는 탭 상자의 경우나 기본적으로 화면에서 벗어나지만 컨트롤 단추를 사용하여 화면상에 슬라이더 전환이 되도록 만들어진 정보 패널과 같은 복잡한 레이아웃 효과를 만드는 데 유용하다.</li> + <li><strong>고정 포지셔닝</strong>는 다른 요소가 아닌 브라우저 뷰포트 기준과 비례해 요소를 고정하는 것을 제외하고는 절대 포지셔닝와 매우 유사합니다. 이것은 나머지 콘텐츠 부분이 스크롤해야 보이는 화면 상에서 항상 동일한 위치에 머물러야 하는 영구적인 탐색 메뉴와 같은 효과를 만드는 데 유용합니다.</li> + <li><strong>스티키 포지셔닝</strong>는 하나의 요소를 <code>position: static</code>와 같이 작동하다가 뷰포트 기준에서 사전에 정의된 간격띄우기 지점에 도달한 순간 이후부터는 <code>position: fixed</code>와 같이 같이 작동하는 새로운 포지셔닝 메서드이다.</li> +</ul> + +<h3 id="간단한_포지셔닝_예제">간단한 포지셔닝 예제</h3> + +<p>이러한 페이지 레이아웃 기술에 친숙해지도록 몇 가지 간단한 예를 보여드리겠습니다. 예제는 다음과 같이 모두 동일한 HTML 특성을 갖고 있다:</p> + +<pre class="brush: html"><h1>포지셔닝</h1> + +<p>나는 기본 블록 수준 요소입니다.</p> +<p class="positioned">나는 기본 블록 수준 요소입니다.</p> +<p>나는 기본 블록 수준 요소입니다.</p></pre> + +<p>이 HTML은 다음과 같은 CSS를 기본값으로 사용하여 스타일링됩니다.</p> + +<pre class="brush: css">body { + width: 500px; + margin: 0 auto; +} + +p { + background-color: rgb(207,232,220); + border: 2px solid rgb(79,185,227); + padding: 10px; + margin: 10px; + border-radius: 5px; +} +</pre> + +<p>렌더링된 출력은 다음과 같다:</p> + +<p>{{ EmbedLiveSample('간단한_포지셔닝_예제', '100%', 300) }}</p> + +<h3 id="상대_포지셔닝">상대 포지셔닝</h3> + +<p>상대 포지셔닝 통해 기본 대열 속에서 예상되는 기본값으로 주어지는 위치로부터 항목을 간격띄우기할 수 있다. 이것은 아이콘을 약간 아래로 이동하여 텍스트 레이블에 맞춰 정렬하는 것과 같은 작업을 수행할 수 있다는 의미다. 이를 위해 다음 규칙을 추가하여 상대적인 위치를 추가할 수 있습니다:</p> + +<pre class="brush: css">.positioned { + position: relative; + top: 30px; + left: 30px; +}</pre> + +<p>여기서 우리는 중간 단락에 {{cssxref("position")}} 값을<code>relative</code>로 부여하고(이것은 자체적으로 아무것도하지 않는다) 아울러 {{cssxref("top")}}와 {{cssxref("left")}} 속성도 추가한다. 이것은 영향을 받는 요소를 아래로 그리고 오른쪽으로 이동시키는 역할을 한다. 이것은 당신이 기대했던 것과 반대되는 것처럼 보일 수 있지만, 그것을 왼쪽과 상단면에서 밀리는 요소로 생각할 필요가 있다.</p> + +<p>이 코드를 추가하면 다음과 같은 결과가 나타난다.</p> + +<div id="상대적_1"> +<div class="hidden"> +<h6 id="상대적_포지셔닝_예제">상대적 포지셔닝 예제</h6> + +<pre class="brush: html"><h1>상대적 포지셔닝</h1> + +<p>나는 기본 블록 수준 요소입니다.</p> +<p class="positioned">이것은 내가 상대적으로 포지셔닝한 요소입니다.</p> +<p>나는 기본 블록 수준 요소입니다.</p></pre> + +<pre class="brush: css">body { + width: 500px; + margin: 0 auto; +} + +p { + background-color: rgb(207,232,220); + border: 2px solid rgb(79,185,227); + padding: 10px; + margin: 10px; + border-radius: 5px; +} +</pre> +</div> + +<pre class="brush: css">.positioned { + position: relative; + background: rgba(255,84,104,.3); + border: 2px solid rgb(255,84,104); + top: 30px; + left: 30px; +}</pre> +</div> + +<p>{{ EmbedLiveSample('상대적_1', '100%', 300) }}</p> + +<h3 id="절대_포지셔닝">절대 포지셔닝</h3> + +<p>절대 포지셔닝는 보통 흐름(normal flow)에서 요소를 완전히 제거하고 컨테이너 블록의 가장자리로부터 간격띄우기값(오프셋)을 사용하여 배치하는 데 사용된다.</p> + +<p>위치 이동이 없던 원래의 예제로 회귀해서 절대 포지셔닝를 구현하기 위해 다음과 같은 CSS 규칙을 추가할 수 있다:</p> + +<pre class="brush: css">.positioned { + position: absolute; + top: 30px; + left: 30px; +}</pre> + +<p>여기서 우리는 중간 단락에 <code>absolute</code> {{cssxref("position")}} 값과 이전과 동일한 {{cssxref("top")}}과 {{cssxref("left")}}속성을 부여한다. 그러나 이 코드를 추가하면 다음과 같은 결과가 나온다.</p> + +<div id="절대_1"> +<div class="hidden"> +<h6 id="절대_포지셔닝_예제">절대 포지셔닝 예제</h6> + +<pre class="brush: html"><h1>절대 포지셔닝</h1> + +<p>나는 기본 블록 수준 요소입니다.</p> +<p class="positioned">이것은 내가 절대적으로 포지셔닝한 요소입니다.</p> +<p>나는 기본 블록 수준 요소입니다.</p></pre> + +<pre class="brush: css">body { + width: 500px; + margin: 0 auto; +} + +p { + background-color: rgb(207,232,220); + border: 2px solid rgb(79,185,227); + padding: 10px; + margin: 10px; + border-radius: 5px; +} +</pre> +</div> + +<pre class="brush: css">.positioned { + position: absolute; + background: rgba(255,84,104,.3); + border: 2px solid rgb(255,84,104); + top: 30px; + left: 30px; +}</pre> +</div> + +<p>{{ EmbedLiveSample('절대_1', '100%', 300) }}</p> + +<p>이건 아주 달라! 위치 지정 요소는 이제 페이지 레이아웃의 나머지 부분과 완전히 분리되어 그 것 위에 놓여있다. 나머지 두 단락은 이제 원래 위치에 있던 자기 형제가 존재하지 않은 듯이 나란히 놓여 있다. {{cssxref("top")}}과 {{cssxref("left")}} 속성은 상대적 위치 지정 요소에 대해 미치는 것과는 다른 영향을 절대적 위치 지정 요소에 대해 미친다. 이 경우 간격띄우기값(오프셋)은 페이지의 좌측 최상단을 기준으로 계산되었다. 여기서 컨테이너가 되는 부모 요소를 변경할 수 있으며 <a href="/en-US/docs/Learn/CSS/CSS_layout/위치잡기">포지셔닝</a>에 관한 단원에서 해당 내용을 살펴보겠다.</p> + +<h3 id="고정_포지셔닝">고정 포지셔닝</h3> + +<p>고정 포지셔닝는 절대 포지셔닝와 같은 방식으로 문서 대열에서 요소를 제거한다. 그러나 컨테이너 위치로부터 간격띄우기를 적용하는 게 아니라 뷰포트를 기준으로 적용된다. 해당 항목이 뷰포트 기준에 비례하여 고정되기 때문에 해당 항목 아래로 페이지가 스크롤할 때 고정된 메뉴 항목과 같은 효과를 생성할 수 있다.</p> + +<p>이번 예제의 경우 페이지를 스크롤할 수 있도록 텍스트 형태의 세 단락으로 구성된 HTML에 상자 하나를 <code>position: fixed</code>로 지정했다.</p> + +<pre class="brush: html"><h1>고정 포지셔닝</h1> + +<div class="positioned">고정</div> + +<p>단락 1.</p> +<p>단락 2.</p> +<p>단락 3.</p> +</pre> + +<div id="고정_1"> +<div class="hidden"> +<h6 id="고정_포지셔닝_예제">고정 포지셔닝 예제</h6> + +<pre class="brush: html"><h1>고정 포지셔닝</h1> + +<div class="positioned">고정</div> + +<p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p> + +<p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed est. Nam id risus quis ante semper consectetur eget aliquam lorem. Vivamus tristique elit dolor, sed pretium metus suscipit vel. Mauris ultricies lectus sed lobortis finibus. Vivamus eu urna eget velit cursus viverra quis vestibulum sem. Aliquam tincidunt eget purus in interdum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p> + +<p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p> + +</pre> + +<pre class="brush: css">body { + width: 500px; + margin: 0 auto; +} + +.positioned { + background: rgba(255,84,104,.3); + border: 2px solid rgb(255,84,104); + padding: 10px; + margin: 10px; + border-radius: 5px; +}</pre> +</div> + +<pre class="brush: css">.positioned { + position: fixed; + top: 30px; + left: 30px; +}</pre> +</div> + +<p>{{ EmbedLiveSample('고정_1', '100%', 200) }}</p> + +<h3 id="흡착_포지셔닝">흡착 포지셔닝</h3> + +<p>흡착 포지셔닝는 우리의 선택을 기다리며 대기중인 마지막 포지셔닝 메서드다. 이것은 기본값인 정적 포지셔닝와 고정 포지셔닝의 혼합형이다. 항목이 <code>position: sticky</code>로 지정된 경우 해당 항목은 뷰포트 기준에서 우리가 정의한 간격띄우기 지점에 도달하기 전까지 보통 흐름(normal flow) 상에서 스크롤된다. 그 지점에 마치 <code>position: fixed</code>가 적용된 것처럼 "철썩" 붙게 된다.</p> + +<div id="흡착_1"> +<div class="hidden"> +<h6 id="흡착_포지셔닝_예제">흡착 포지셔닝 예제</h6> + +<pre class="brush: html"><h1>흡착 포지셔닝</h1> + +<p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p> + +<div class="positioned">흡착</div> + +<p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed est. Nam id risus quis ante semper consectetur eget aliquam lorem. Vivamus tristique elit dolor, sed pretium metus suscipit vel. Mauris ultricies lectus sed lobortis finibus. Vivamus eu urna eget velit cursus viverra quis vestibulum sem. Aliquam tincidunt eget purus in interdum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p> + +<p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p> </pre> + +<pre class="brush: css">body { + width: 500px; + margin: 0 auto; +} + +.positioned { + background: rgba(255,84,104,.3); + border: 2px solid rgb(255,84,104); + padding: 10px; + margin: 10px; + border-radius: 5px; +}</pre> +</div> + +<pre class="brush: css">.positioned { + position: sticky; + top: 30px; + left: 30px; +}</pre> +</div> + +<p>{{ EmbedLiveSample('흡착_1', '100%', 200) }}</p> + +<div class="note"> +<p><strong>참고</strong>: 포지셔닝에 대해 더 알아보고 싶다면 <a href="/kr/docs/Learn/CSS/CSS_layout/위치잡기">포지셔닝</a> 단원을 보라.</p> +</div> + +<h2 id="테이블_레이아웃">테이블 레이아웃</h2> + +<p>HTML 테이블은 표로 나타낸 데이터를 표시하기에는 무난했다. 그러나 (수년 전, 심지어 기초적인 CSS가 여러 브라우저에서 안정적으로 지원되기 이전에도) 웹 개발자들은 머리글, 바닥글, 서로 다른 단 등을 여러가지 테이블 행과 열에 집어넣어 웹페이지 전체 레이아웃을 짜는데 테이블을 사용하기도 했다. 이것은 당시에는 먹혔지만, 많은 문제가 상존했다. 테이블 레이아웃은 유연하지 않고, 마크업이 과도하고, 디버그하기 어렵고, 의미론적으로 맞지 않았다(예: 스크린 리더 사용자는 테이블 레이아웃을 탐색하는 데 문제가 있다).</p> + +<p>테이블 마크업을 사용할 때 테이블이 웹 페이지에 보여지는 방식의 재원(財源)은 테이블 레이아웃을 정의하는 CSS 속성 집합이다. 이러한 속성은 테이블이 아닌 요소를 배치하는 데 사용할 수 있으며, 이 용법은 때때로 "CSS 테이블 용법"으로 기술된다.</p> + +<p>아래 예는 이러한 용법을 보여준다. 레이아웃에 CSS 테이블을 사용하는 것은 이 시점에서 낡은 메서드로 간주되어야 한다. flexbox 또는 그리드 레이아웃이 지원되지 않던 매우 오래된 브라우저를 사용하는 사람의 경우에 해당된다.</p> + +<p>예제를 살펴보자. 우선, HTML 양식을 생성하는 몇 가지 간단한 마크업 사례다. 개별 입력 요소에는 레이블이 달려있으며, 단락 안에는 캡션도 포함시켰다. 각 한 쌍을 이루는 레이블과 입력 요소는 레이아웃 목적에 따라 {{htmlelement("div")}} 요소에 둘러싸여 있다.</p> + +<pre class="brush: html"><form> + <p>우선, 이름과 나이를 말씀해주세요</p> + <div> + <label for="이름">이름:</label> + <input type="text" id="이름"> + </div> + <div> + <label for="성">성:</label> + <input type="text" id="성"> + </div> + <div> + <label for="나이">나이:</label> + <input type="text" id="나이"> + </div> +</form></pre> + +<p>이제 우리 예제에 해당되는 CSS 차례다. CSS의 대부분은 {{cssxref("display")}} 속성을 사용한 것을 제외하면 대체로 평범한 내용이다. {{htmlelement("form")}}와 복수의 {{htmlelement("div")}}, {{htmlelement("label")}}, {{htmlelement("input")}}는 각기 테이블과 복수의 테이블 행, 테이블 셀을 표시하라는 주문을 받는다. 기본적으로 그들은 HTML 테이블 마크업과 같이 동작하며 기본값으로 레이블과 입력 양식 요소를 멋지게 정렬시킨다. 이제 우리가 해야할 일은 모든 요소가 좀더 멋지게 보이도록 크기와 여백을 조금 추가하는 것이다. 그러면 일이 마무리된다.</p> + +<p>눈치 챘겠지만, 캡션 단락은 <code>display: table-caption;</code>가 부여되어 테이블 {{htmlelement("caption")}}과 같이 동작하게 만들었고, 또한 <code>display: table-caption;</code>를 부여하며 해당 마크업이 소스 코드에서 <code><input></code> 요소보다 선행함에도 해당 캡션이 스타일 목적에 따라 테이블 하단에 놓이도록 했다. 이렇듯 약간의 유연성이 허용된다.</p> + +<pre class="brush: css">html { + font-family: sans-serif; +} + +form { + display: table; + margin: 0 auto; +} + +form div { + display: table-row; +} + +form label, form input { + display: table-cell; + margin-bottom: 10px; +} + +form label { + width: 200px; + padding-right: 5%; + text-align: right; +} + +form input { + width: 300px; +} + +form p { + display: table-caption; + caption-side: bottom; + width: 300px; + color: #999; + font-style: italic; +}</pre> + +<p>이것은 우리에게 다음과 같은 결과를 제공합니다.</p> + +<p>{{ EmbedLiveSample('테이블_레이아웃', '100%', '170') }}</p> + +<p>이 예제 역시 여기 <a href="https://mdn.github.io/learning-area/css/styling-boxes/box-model-recap/css-tables-example.html">CSS 테이블 예제</a>에서 라이브로 볼 수 있고, 이곳 <a href="https://github.com/mdn/learning-area/blob/master/css/styling-boxes/box-model-recap/css-tables-example.html">소스 코드</a>에서도 역시 볼 수 있다.</p> + +<h2 id="다단_레이아웃">다단 레이아웃</h2> + +<p>다단 레이아웃 모듈은 텍스트가 신문지상에 나열되는 방식과 비슷하게 내용을 단 형태로 레이아웃할 수 있는 방법을 제공한다. 단을 따라 위아래 읽기는 사용자가 위아래로 스크롤하도록 강제하길 원하지 않는다면 웹 상황에서 덜 유용하다. 다만 콘텐츠를 단에 배치하는 것은 유용한 기술일 수 있다.</p> + +<p>한 블록을 다단 컨테이너 속으로 들여넣으려면 {{cssxref("column-count")}} 속성을 사용하여 브라우저에게 우리가 몇 단으로 나누길 원하는지 밝히거나 {{cssxref("column-width")}} 속성을 사용하여 브라우저에게 몇 단이 됐건 최소 해당 너비만한 단으로 컨테이너를 채우라고 말하면 된다.</p> + +<p>아래 예제에서 내부에 일명 <code>container</code> 클래스 해당하는 <code><div></code> 요소를 포함하는 HTML 블록을 가지고 시작한다.</p> + +<pre class="brush: html"><div class="container"> + <h1>다단 레이아웃</h1> + + <p>단락 1.</p> + <p>단락 2.</p> + +</div> +</pre> + +<p>우리는 해당 컨테이너에 200픽셀의 단 너비를 사용해서 브라우저가 컨테이너에 맞아 떨어지도록 최대 200픽셀의 단을 만들며, 그 뒤에 생성된 단 사이 나머지 공간을 나눠쓰게 된다.</p> + +<div id="다단_1"> +<div class="hidden"> +<h6 id="다단_예제">다단 예제</h6> + +<pre class="brush: html"> <div class="container"> + <h1>다단 레이아웃</h1> + + <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p> + + + <p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed est. Nam id risus quis ante semper consectetur eget aliquam lorem. Vivamus tristique elit dolor, sed pretium metus suscipit vel. Mauris ultricies lectus sed lobortis finibus. Vivamus eu urna eget velit cursus viverra quis vestibulum sem. Aliquam tincidunt eget purus in interdum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p> + + </div> + </pre> + +<pre class="brush: css">body { max-width: 800px; margin: 0 auto; } </pre> +</div> + +<pre class="brush: css"> .container { + column-width: 200px; + }</pre> +</div> + +<p>{{ EmbedLiveSample('다단_1', '100%', 200) }}</p> + +<h2 id="요약정리">요약정리</h2> + +<p>이번 글에서는 알아야 할 모든 레이아웃 기술에 대한 요약을 간단하게 제공했습니다. 개별 기술에 대한 자세한 내용을 계속 읽어보세요!</p> + +<p>{{NextMenu("Learn/CSS/CSS_layout/Normal_Flow", "Learn/CSS/CSS_layout")}}</p> + +<h2 id="이번_단위에는">이번 단위에는</h2> + +<ul> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Introduction">CSS 레이아웃 소개</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/일반_흐름">보통 흐름(normal flow)</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Flexbox">flexbox</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Grids">그리드</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Floats">Floats</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/위치잡기">포지셔닝</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Multiple-column_Layout">다단 레이아웃</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Responsive_Design">반응형 디자인</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/%EB%AF%B8%EB%94%94%EC%96%B4_%EC%BF%BC%EB%A6%AC_%EC%B4%88%EB%B3%B4%EC%9E%90_%EC%95%88%EB%82%B4%EC%84%9C">미디어 쿼리 초보자 안내서</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Legacy_Layout_Methods">레거시 레이아웃 메서드</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Supporting_Older_Browsers">이전 브라우저 지원</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Fundamental_Layout_Comprehension">레이아웃 이해도 필수 평가</a></li> +</ul> diff --git a/files/ko/learn/css/css_layout/legacy_layout_methods/index.html b/files/ko/learn/css/css_layout/legacy_layout_methods/index.html new file mode 100644 index 0000000000..aca6565fd7 --- /dev/null +++ b/files/ko/learn/css/css_layout/legacy_layout_methods/index.html @@ -0,0 +1,588 @@ +--- +title: 레거시 조판 메서드 +slug: Learn/CSS/CSS_layout/Legacy_Layout_Methods +tags: + - 격자 시스템 + - 레거시 + - 부동체 + - 씨에스에스 + - 안내서 + - 조판 + - 초보자 + - 학습 +translation_of: Learn/CSS/CSS_layout/Legacy_Layout_Methods +--- +<div>{{LearnSidebar}}</div> + +<p>{{PreviousMenuNext("Learn/CSS/CSS_layout/Media_queries", "Learn/CSS/CSS_layout/Supporting_Older_Browsers", "Learn/CSS/CSS_layout")}}</p> + +<p class="summary">격자 시스템은 씨에스에스 조판에서 사용되는 매우 일반적인 기능이며, 씨에스에스 격자 조판 이전에는 부동체 또는 기타 조판 기능을 이용하여 격자 조판이 구현되는 경향이 있었습니다. 당신의 조판을 정해진 수의 열(예를 들어 4, 6 또는 12열)이라 상상한 뒤 당신의 콘텐츠 열을 그 가상의 열 안에 끼워맞춥니다. 이 문서에서 우리는 이 오래된 메서드가 어떻게 작동하는지 탐구할 것입니다. 이는 여러분이 오래된 프로젝트에 몸을 담게 될 경우에 그들 메서드의 사용 방법에 대한 이해를 돕기 위함입니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">선결 사항:</th> + <td>HTML 기본 (<a href="/ko/docs/Learn/HTML/Introduction_to_HTML">에이치티엠엘 입문</a> 학습), 씨에스에스의 작동 방식 <a href="/ko/docs/Learn/CSS/Introduction_to_CSS">씨에스에스 입문 </a> 및 (<a href="/ko/docs/Learn/CSS/Styling_boxes">박스 양식 지정</a> 학습)</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>씨에스에스 격자 조판 이전에 사용된 격자 조판 시스템의 기본 개념을 브라우저에서 사용할 수 있습니다.</td> + </tr> + </tbody> +</table> + +<h2 id="씨에스에스_격자_조판_이전의_조판_및_격자_시스템">씨에스에스 격자 조판 이전의 조판 및 격자 시스템</h2> + +<p>씨에스에스가 아주 최근까지 내장된 격자 시스템을 갖고 있지 않았고, 그 대신 격자와 같은 디자인 생성을 위해 최적화에 못 미치는 다양한 방법을 사용했다니 디자인 배경의 경력자 관점에서 보면 놀랍게 보일 듯합니다. 우리는 이제 이것을 "래거시"라고 부릅니다.</p> + +<p>새로운 프로젝트의 경우 모든 조판의 기초를 형성하기 위해 대체로 씨에스에스 격자 조판이 하나 이상의 다른 현대 조판 메서드와 연동되어 사용됩니다. 그러나 여러분은 이러한 레거시 메서드를 사용하는 "격자 시스템"을 수시로 접하게 될겁니다. 그들 레거시 메서드의 작동 방식, 그리고 씨에스에스 격자 조판과 다른 이유에 대해 이해할 가치가 있습니다.</p> + +<p>이번 단원은 부동체와 가변상자 작동 방식을 기반으로 한 격자 시스템과 격자 프레임워크가 어떻게 작동하는지 설명합니다. 당신이 격자 조판을 공부한 상태라면 이 모든 것이 얼마나 복잡해 보이는지 놀랄 겁니다! 이러한 지식은 새로운 메서드를 지원하지 않는 브라우저를 위한 대체 코드를 작성해야 할 경우에 도움이 될 뿐만 아니라 이러한 유형의 시스템을 사용하는 기존 프로젝트에서 작업할 수 있게 해줄 것입니다.</p> + +<p>우리가 이들 격자 시스템을 탐구할 때, 그것들 중 어느 것도 씨에스에스 격자 조판(CSS Grid Layout)이 격자를 만드는 방식으로 격자를 만들지는 않는다는 사실을 염두에 두어야 합니다. 그들은 항목의 크기를 부여하고, 항목 무리 주변을 밀어내어 격자 <em>모양</em>처럼 정렬해 보여주는 식으로 작동합니다.</p> + +<h2 id="2열_조판">2열 조판</h2> + +<p>가능한 가장 간단한 예시인 두 개의 열 조판으로 시작하겠습니다. 아래 내용을 따라하려면 당신의 컴퓨터에 <code>index.html</code> 파일을 새로 작성하여, 거기에 <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/getting-started/index.html">간단한 HTML 템플릿</a>으로 채우고, 파일 내부의 적절한 위치에 아래 코드를 삽입하면 됩니다. 해당 섹션의 맨 아래에는 최종 코드가 어떻게 생겼는지에 대한 실제 예제가 있습니다.</p> + +<p>우선, 우리는 칼럼에 넣을 몇 가지 콘텐츠가 필요합니다. 현재 에이치티엠엘의 바디 내부에 있는 것을 아래 내용으로 대체하십시요:</p> + +<pre class="brush: html"><h1>2열 조판 예제</h1> +<div> + <h2>첫 번째 열</h2> + <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p> +</div> + +<div> + <h2>두 번째 열</h2> + <p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed est. Nam id risus quis ante semper consectetur eget aliquam lorem. Vivamus tristique elit dolor, sed pretium metus suscipit vel. Mauris ultricies lectus sed lobortis finibus. Vivamus eu urna eget velit cursus viverra quis vestibulum sem. Aliquam tincidunt eget purus in interdum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p> +</div></pre> + +<p>각 열에는 자체 콘텐츠를 포함하게 되고, 모든 콘텐츠를 한꺼번에 조작할 수 있게 해주는 외부 요소가 필요합니다. 이번 예제에서 우리는 {{htmlelement("div")}}를 선택했지만, 당신은 {{htmlelement("article")}}와 복수의 {{htmlelement("section")}}, {{htmlelement("aside")}}, 그 밖에 무엇이 됐건 한층 의미적으로 적절한 것을 선택할 수 있습니다.</p> + +<p>이제 씨에스에스 내용입니다. 우선 다음을 HTML에 적용해 몇 가지 기본적인 설정을 제공합니다.</p> + +<pre class="brush: css">body { + width: 90%; + max-width: 900px; + margin: 0 auto; +}</pre> + +<p>에이치티엠엘 바디 요소는 900px의 너비가 될 때까지 뷰포트 너비의 90%를 차지할 것이며, 이 경우 그 너비에 고정될 것이며, 뷰포트 안에 중심부에 자신을 위치시킬 겁니다. 기본값으로 바디 요소의 자녀들({{htmlelement("h1")}}와 두 개의 {{htmlelement("div")}}는 바디 너비 100%까지 확장될 것입니다. 두 개의 {{htmlelement("div")}}가 나란히 부동하길 원한다면, 자녀 요소의 너비를 부모 요소의 너비의 총합계가 100% 또는 그 이하로 설정해 상대 요소와 나란히 들어맞을 수 있도록 해야 합니다. 다음을 당신의 씨에스에스의 맨 아래에 추가하세요:</p> + +<pre class="brush: css">div:nth-of-type(1) { + width: 48%; +} + +div:nth-of-type(2) { + width: 48%; +}</pre> + +<p>여기서 우리는 두 요소의 너비를 부모 요소의 48%로 설정했습니다. 너비의 총합은 96%로써 결국 4% 남는 공간이 두 열 사이의 배수구 역할을 하게 됩니다. 이제 우리는 열을 부동(浮動)시킬 필요가 있습니다. 다음과 같이:</p> + +<pre class="brush: css">div:nth-of-type(1) { + width: 48%; + float: left; +} + +div:nth-of-type(2) { + width: 48%; + float: right; +}</pre> + +<p>이 모든 것을 종합하면 다음과 같은 결과가 나와야 합니다.</p> + +<div id="부동_2열"> +<div class="hidden"> +<h6 id="단순한_2열_조판">단순한 2열 조판</h6> + +<pre class="brush: html"><h1>2 column layout example</h1> + +<div> + <h2>첫 번째 열</h2> + <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p> +</div> + +<div> + <h2>두 번째 열</h2> + <p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed est. Nam id risus quis ante semper consectetur eget aliquam lorem. Vivamus tristique elit dolor, sed pretium metus suscipit vel. Mauris ultricies lectus sed lobortis finibus. Vivamus eu urna eget velit cursus viverra quis vestibulum sem. Aliquam tincidunt eget purus in interdum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p> +</div> +</pre> + +<pre class="brush: css">body { + width: 90%; + max-width: 900px; + margin: 0 auto; +} + +div:nth-of-type(1) { + width: 48%; + float: left; +} + +div:nth-of-type(2) { + width: 48%; + float: right; +} +</pre> +</div> +</div> + +<p>{{ EmbedLiveSample('부동_2열', '100%', 520) }}</p> + +<p>여기서 여러분은 우리가 모든 너비에 대해 백분율을 사용하고 있음을 알아차릴 것입니다. 이것은 <strong>liquid layout</strong>을 생성하기 때문에 꽤 좋은 전략입니다. 이것은 서로 다른 화면 크기에 적응하고 더 작은 화면 크기에서 열 너비에 대해 동일한 비율을 유지하게 됩니다. 브라우저 창의 너비를 조정해 보십시오. 이같은 특징은 반응형 웹 디자인을 위한 귀중한 도구입니다.</p> + +<div class="note"> +<p><strong>참고</strong>: 당신은 이 예제가 작종하는 장면을 여기서 <a href="http://mdn.github.io/learning-area/css/css-layout/floats/0_two-column-layout.html">0_two-column-layout.html</a> 볼 수 있습니다. (또한, 여기 <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/floats/0_two-column-layout.html">소스 코드</a>)도 있다.</p> +</div> + +<h2 id="간단한_레거시_격자_프레임워크_생성하기">간단한 레거시 격자 프레임워크 생성하기</h2> + +<p>레거시 프레임 워크의 대부분은 격자처럼 보이는 것을 만들기 위해한 열을 다른 열 옆에 부동시키기 위해 {{cssxref("float")}} 속성의 동작을 이용합니다. 부동을 포함한 격자 생성 과정을 통해 이 방법이 어떻게 작동하는지 여러분에게 보여주고, 여러분이 <a href="/ko/docs/Learn/CSS/CSS_layout/Floats">부동 및 해제</a> 단원에서 배운 것을 바탕으로 능력을 배가하기 위해 더 발전된 개념을 도입합니다.</p> + +<p>격자 프레임워크를 생성할 수 있는 가장 편리하게 유형은 고정 너비입니다. 즉, 우리는 우리가 목표로 하는 디자인의 총 너비, 우리가 원하는 열의 수, 배수로의 너비 및 열의 너비를 계산할 필요가 있습니다. 대신 브라우저 너비에 따라 커지고 축소되는 열이 있는 격자상에 디자인을 배치하기로 한다면 열 무리에 대한 백분율 너비와 열 사이 배수로 너비를 계산해야 할 겁니다.</p> + +<p>다음 절에서는 두 가지를 어떻게 생성할지 살펴볼 것입니다. 우리는 12개의 열 격자를 생성할 것입니다. 12열이 6, 4, 3, 2로 잘 나눌 수 있다는 점을 감안할 때, 매우 일반적인 선택입니다.</p> + +<h3 id="간단한_고정_너비_격자">간단한 고정 너비 격자</h3> + +<p>먼저 고정 너비 열을 사용하는 격자 시스템을 생성해 봅시다.</p> + +<p>먼저, 우리 예제인 <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/grids/simple-grid.html">simple-grid.html</a> 사본 파일을 만듭니다. 여기에는 바디 부분에 다음과 같은 마크업을 포함하고 있습니다.</p> + +<pre class="brush: html"><div class="wrapper"> + <div class="row"> + <div class="col">1</div> + <div class="col">2</div> + <div class="col">3</div> + <div class="col">4</div> + <div class="col">5</div> + <div class="col">6</div> + <div class="col">7</div> + <div class="col">8</div> + <div class="col">9</div> + <div class="col">10</div> + <div class="col">11</div> + <div class="col">12</div> + </div> + <div class="row"> + <div class="col span1">13</div> + <div class="col span6">14</div> + <div class="col span3">15</div> + <div class="col span2">16</div> + </div> +</div></pre> + +<p>우리의 목표는 이것을 12열 격자상에 2행 격자를 시연하는 것입니다. 상단 행은 개별 열의 크기를 나타내고 두 번째 행은 격자 크기가 서로 다른 영역입니다.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13901/simple-grid-finished.png" style="display: block; height: 50px; margin: 0px auto; width: 952px;"></p> + +<p>{{htmlelement("style")}} 요소에는 외곽(래퍼) 컨테이너에 980픽셀의 너비를 부여하는 아래와 같은 코드를 추가하고 오른쪽에 패딩으로는 20픽셀 우측을 추가합니다. 이로써 열 및 배수로의 총 너비를 위해 960픽셀이 주어집니다. 이 경우, 사이트의 모든 요소에 {{cssxref("box-sizing")}}을 <code>border-box</code>로 설정했기 때문에 패딩은 총 콘텐츠 너비에서 제외할 수 있습니다(자세한 설명은 <a href="/en-US/docs/Learn/CSS/Styling_boxes/Box_model_recap#Changing_the_box_model_completely">상자 모델의 전면 변경</a>을 참조하세요).</p> + +<pre class="brush: css">* { + box-sizing: border-box; +} + +body { + width: 980px; + margin: 0 auto; +} + +.wrapper { + padding-right: 20px; +}</pre> + +<p>이제 격자의 각 행을 둘러싸는 행 컨테이너를 사용하여 한 행을 다른 행으로부터 정리하여 구분합니다. 다음과 같은 규칙을 이전 규칙 아래에 추가하십시요:</p> + +<pre class="brush: css">.row { + clear: both; +}</pre> + +<p>이렇게 정리를 적용한다는 것은 요소 무리가 딸린 각각의 행을 요소 무리로 가득 채울 필요가 없다는 것을 의미합니다. 행은 계속 분리된 채로 있으며, 서로 간섭하지 않습니다.</p> + +<p>열 사이의 배수로는 20픽셀 너비입니다. 컨테이너의 우측 편에 패딩 20픽셀을 부여해 균형을 잡기 위해 첫 번째 열을 포함하여 각 열의 왼편에 여백의 형태로 배수로를 생성했습니다. 그래서 우리는 총 12개의 배수로 가지고 있습니다. 따라서 12 x 20 = 240입니다.</p> + +<p>우리는 총 너비 960 픽셀에서 배수로 부분을 빼야 함으로 우리의 열 무리를 위해 720픽셀이 주어집니다. 당장에 그것을 12로 나눈다면, 각 열은 60 픽셀이어야 한다는 것을 알 수 있습니다.</p> + +<p>다음 단계는 클래스 <code>.col</code>에 대한 규칙을 생성하는 일입니다. 동 클래스에 속한 요소를 왼쪽으로 부동시키고, 배수구를 형성하기 위해 20픽셀의 {{cssxref("margin-left")}}와 60픽셀의 {{cssxref("width")}} 값을 동 요소에 부여합니다. 다음 규칙을 당신의 씨에스에스의 맨 아래에 추가하십시요:</p> + +<pre class="brush: css">.col { + float: left; + margin-left: 20px; + width: 60px; + background: rgb(255, 150, 150); +}</pre> + +<p>이제 단일 열 무리 형태의 상단 행은 격자처럼 깔끔하게 배치됩니다.</p> + +<div class="note"> +<p><strong>주석</strong>: 각 열에 밝은 빨간색 색상을 부여하여 각 공간이 얼마나 많은지 정확하게 볼 수 있습니다.</p> +</div> + +<p>두 개 이상의 열을 하나로 합치길 원하는 조판 컨테이너에 대해선 해당 컨테이너에 {{cssxref("width")}} 값을 필요한(합치기 할) 열 갯수에 맞춰(아울러 열 사이 배수구 숫자까지 포함해) 조정하기 위해 특별한 클래스를 부여할 필요가 있습니다. 우리는 컨테이너 무리가 2열에서 12열까지 (원하는 열 갯수만큼) 하나로 합치기할 수 있도록 추가 클래스를 만들 필요가 있습니다. 각 열의 너비는 (하나로 합쳐질) 해당 열 갯수의 열 너비와 배수구 너비를 합산한 결과입니다. 여기서 배수구 숫자는 항상 열 갯수에서 하나가 빠집니다.</p> + +<p>당신의 씨에스에스 맨 아래에 다음을 추가하십시요.</p> + +<pre class="brush: css">/* Two column widths (120px) plus one gutter width (20px) */ +.col.span2 { width: 140px; } +/* Three column widths (180px) plus two gutter widths (40px) */ +.col.span3 { width: 220px; } +/* And so on... */ +.col.span4 { width: 300px; } +.col.span5 { width: 380px; } +.col.span6 { width: 460px; } +.col.span7 { width: 540px; } +.col.span8 { width: 620px; } +.col.span9 { width: 700px; } +.col.span10 { width: 780px; } +.col.span11 { width: 860px; } +.col.span12 { width: 940px; }</pre> + +<p>이러한 클래스를 생성해 놓았다면 격자에 서로 다른 너비의 열 무리를 배치할 수 있습니다. 페이지를 저장하고 브라우저에 불러들여 효과를 확인하십시오.</p> + +<div class="note"> +<p><strong>참조</strong>: 위의 예제를 제대로 적용하기가 어렵다면 깃허브에 있는 <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/grids/simple-grid-finished.html">완성된 버전</a>과 비교해보라. (<a href="http://mdn.github.io/learning-area/css/css-layout/grids/simple-grid-finished.html">라이브로도 보세요</a>).</p> +</div> + +<p>당신의 요소 무리에 적용한 클래스를 수정하거나 일부 컨테이너를 추가 및 제거해보며 당신이 어떻게 조판에 변경을 가할 수 있는지 확인하십시오 예를 들어 두 번째 행을 이렇게 만들 수 있습니다:</p> + +<pre class="brush: css"><div class="row"> + <div class="col span8">13</div> + <div class="col span4">14</div> +</div></pre> + +<p>이제 격자 시스템이 작동합니다. 여러분은 단순히 행 무리를 정의하고 각 행에 열 갯수를 정의한 다음 각 컨테이너에 필요한 내용을 채울 수 있습니다. 대단하죠!</p> + +<h3 id="유동_격자_생성하기">유동 격자 생성하기</h3> + +<p>우리 격자는 잘 작동하지만, 고정 너비를 가지고 있습니다. 우리는 브라우저 {{Glossary("viewport")}}에서 사용 가능한 공간과 함께 확대되고 축소될 가변 (유동) 격자를 정말로 원합니다. 이를 위해 기준 픽셀 너비를 백분율로 바꿀 수 있습니다.</p> + +<p>고정 너비를 유연한 백분율 기반으로 변환하는 방정식은 다음과 같습니다.</p> + +<pre>target / context = result</pre> + +<p>열 너비의 경우 목표 너비는 60픽셀이고 콘텐츠는 래퍼 클래스의 총합 960픽셀입니다. 우리는 백분율을 계산하기 위해 다음을 사용할 수 있습니다.</p> + +<pre>60 / 960 = 0.0625</pre> + +<p>그리고 나서 우리는 소수점을 2자리 옮기면 백분율 6.25%가 주어집니다. 그래서 우리의 씨에스에스에서 60픽셀의 열 너비를 6.25%로 대체할 수 있습니다.</p> + +<p>우리는 여러분의 배수로 너비에도 똑같이 적용해야 합니다.</p> + +<pre>20 / 960 = 0.02083333333</pre> + +<p>따라서 우리는 <code>.col</code> 규칙에 있는 20픽셀의 {{cssxref("margin-left")}}과 <code>.wrapper</code> 규칙에 있는 20픽셀의 {{cssxref("padding-right")}}를 2.08333333%로 대체해야 합니다.</p> + +<h4 id="여러분의_격자_업데이트_하기">여러분의 격자 업데이트 하기</h4> + +<p>이번 절을 시작하려면 이전 예제 페이지의 새 사본을 만들거나 <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/grids/simple-grid-finished.html">simple-grid-finished.html</a>를 착수파일로 사용하십시요.</p> + +<p>다음과 같이 (<code>.wrapper</code> 선택기에 해당하는) 두 번째 씨에스에스 규칙을 업데이트 하십시요:</p> + +<pre class="brush: css">body { + width: 90%; + max-width: 980px; + margin: 0 auto; +} + +.wrapper { + padding-right: 2.08333333%; +}</pre> + +<p>우리는 백분율 너비를 부여했을뿐만 아니라 조판이 과도하게 확대되는 것을 막기 위해 {{cssxref("max-width")}} 속성을 추가했습니다.</p> + +<p>다음은 아래와 같이 (<code>.col</code> 선택기에 해당하는) 네 번째 씨에스에스 규칙을 업데이트 하십시요:</p> + +<pre class="brush: css">.col { + float: left; + margin-left: 2.08333333%; + width: 6.25%; + background: rgb(255, 150, 150); +}</pre> + +<p>이제 약간 노동력이 투여되어야 할 부분이 있습니다. 픽셀 너비보다는 백분율을 사용하기 위해 모든 <code>.col.span</code> 규칙을 업데이트해야 합니다. 계산기를 사용하려면 시간이 좀 걸립니다. 여러분들의 노력을 아끼기 위해, 아래와 같이 여러분을 대신에 우리가 마무리지었습니다.</p> + +<p>다음을 통해 씨에스에스 규칙의 하위 블록을 업데이트합니다.</p> + +<pre class="brush: css">/* Two column widths (12.5%) plus one gutter width (2.08333333%) */ +.col.span2 { width: 14.58333333%; } +/* Three column widths (18.75%) plus two gutter widths (4.1666666) */ +.col.span3 { width: 22.91666666%; } +/* And so on... */ +.col.span4 { width: 31.24999999%; } +.col.span5 { width: 39.58333332%; } +.col.span6 { width: 47.91666665%; } +.col.span7 { width: 56.24999998%; } +.col.span8 { width: 64.58333331%; } +.col.span9 { width: 72.91666664%; } +.col.span10 { width: 81.24999997%; } +.col.span11 { width: 89.5833333%; } +.col.span12 { width: 97.91666663%; }</pre> + +<p>이제 코드를 저장하고 브라우저에 내용을 불러들이면 뷰포트 너비를 변경해보십시오. 열 너비가 멋지게 조정되는 것을 볼 수 있어야 합니다.</p> + +<div class="note"> +<p><strong>참조</strong>: 위의 예제를 제대로 적용하기가 어렵다면 깃허브에 있는 <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/grids/fluid-grid.html">완성된 버전</a>과 비교해보라. (<a href="http://mdn.github.io/learning-area/css/css-layout/grids/fluid-grid.html">라이브로도 보세요</a>).</p> +</div> + +<h3 id="calc_함수를_사용한_편리한_계산법">calc() 함수를 사용한 편리한 계산법</h3> + +<p>씨에스에스 내부에서 직접 calc() 함수를 사용하여 수학 계산을 할 수 있습니다. 이것은 여러분의 씨에스에스 값에 단순한 수학 방정식을 삽입하고 값이 무엇인지 계산할 수 있게 해줍니다. 복잡한 수학이 있을 때 특히 유용하며, 예를 들어 "나는 이 요소의 높이가 항상 부모의 높이의 100% 마이너스 50px가 되기를 원한다"와 같은 서로 다른 단위를 사용하는 셈법까지 계산할 수 있습니다. <a href="/ko/docs/Web/API/MediaRecorder_API/Using_the_MediaRecorder_API#Keeping_the_interface_constrained_to_the_viewport_regardless_of_device_height_with_calc()">MediaRecorder API 자습서에 있는 예제를 보십시요</a>.</p> + +<p>어쨌든, 다시 여러분의 격자로 복귀합시다! 여러분의 격자에서 한 열 이상을 하나로 합치기하고자 하는 어떤 열은 총 너비가 6.25%이고, 거기에 하나로 합치기할 열 갯수를 곱하고, 거기에 2.08333333%를 배수로 갯수로 곱하기합니다(실제 배수로의 갯수는 항상 열 갯수에서 하나 빼기가 됩니다.) 여러분은 <code>calc()</code> 함수을 통해서 여러분이 이러한 셈법을 너비 값 내부에서 바로 계산을 할 수 있으므로, 4열 합치기할 항목에 대해서는 다음과 같이 할 수 있습니다.</p> + +<pre class="brush: css">.col.span4 { + width: calc((6.25%*4) + (2.08333333%*3)); +}</pre> + +<p>여러분의 씨에스에스 규칙의 하단 블록을 다음 값으로 대체한 다음 브라우저에서 다시 불러들여 동일한 결과를 얻을 수 있는지 확인하십시오:</p> + +<pre class="brush: css">.col.span2 { width: calc((6.25%*2) + 2.08333333%); } +.col.span3 { width: calc((6.25%*3) + (2.08333333%*2)); } +.col.span4 { width: calc((6.25%*4) + (2.08333333%*3)); } +.col.span5 { width: calc((6.25%*5) + (2.08333333%*4)); } +.col.span6 { width: calc((6.25%*6) + (2.08333333%*5)); } +.col.span7 { width: calc((6.25%*7) + (2.08333333%*6)); } +.col.span8 { width: calc((6.25%*8) + (2.08333333%*7)); } +.col.span9 { width: calc((6.25%*9) + (2.08333333%*8)); } +.col.span10 { width: calc((6.25%*10) + (2.08333333%*9)); } +.col.span11 { width: calc((6.25%*11) + (2.08333333%*10)); } +.col.span12 { width: calc((6.25%*12) + (2.08333333%*11)); }</pre> + +<div class="note"> +<p><strong>참고</strong>: 여러분은 최종 버전을 <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/grids/fluid-grid-calc.html">fluid-grid-calc.html</a>에서 확인할 수 있습니다. (<a href="http://mdn.github.io/learning-area/css/css-layout/grids/fluid-grid-calc.html">라이브로도 보세요</a>).</p> +</div> + +<div class="note"> +<p><strong>참고</strong>: 여러분의 실습 과정에서 이 같은 내용이 제대로 작동되지 않았다면 여러분의 브라우저가 <code>calc()</code> 함수를 지원하지 않기 때문일 수 있습니다. 다만 이 함수는 멀게는 인터넷 익스플로러 9까지 브라우저 구분없이 지원됩니다.</p> +</div> + +<h3 id="말_되는_VS_“말_안되는”_격자_시스템">말 되는 VS “말 안되는” 격자 시스템</h3> + +<p>조판을 정의하기 위해 여러분의 마크업에 클래스를 추가하면 콘텐츠와 마크업이 시각적 프리젠테이션과 결부됩니다. 당신은 때때로 콘텐츠를 설명하는 클래스에 말되는 이름을 사용하기보다는 콘텐츠가 어떻게 보일지 설명하는 "말 안되는" 이름을 사용하는 씨에스에스 클래스 용례를 접하게 됩니다. 여기서 <code>span2</code>, <code>span3</code>, 기타 등등과 같은 클래스의 경우가 그렇습니다.</p> + +<p>이런 식의 접근 방법만 있는게 아닙니다. 대신 여러분이 격자를 결정한 다음 말 되게 명명된 기존 클래스 규칙에 크기 정보를 추가할 수 있습니다. 예를 들어, 여러분이 8열을 하나로 합치기 원하는 {{htmlelement("div")}} 요소에 <code>content</code>라는 클래스를 부여할 경우 <code>span8</code> 클래스가 출처인 너비 계산값을 복사해 쓸 수 있는데, 그와 같은 규칙은 이렇게 제공됩니다:</p> + +<pre class="brush: css">.content { + width: calc((6.25%*8) + (2.08333333%*7)); +}</pre> + +<div class="note"> +<p><strong>참고</strong>: 당신이 <a href="http://sass-lang.com/">Sass</a>와 같은 전처리기를 사용하려면, 당신을 위해 해당 값을 삽입해주는 간단한 <code>maxin</code>를 생성할 수 있다.</p> +</div> + +<h3 id="격자_내부에_컨테이너_오프셋_가동">격자 내부에 컨테이너 오프셋 가동</h3> + +<p>우리가 생성한 격자는 컨테이너 무리 전체를 격자의 왼쪽편과 일치시켜 출발하길 원하는 경우에 잘 작동합니다. 첫 번째 컨테이너 또는 컨테이너 사이에 빈 열 공간을 남기고 싶다면 여러분의 사이트에 왼쪽 여백을 추가하여 격자를 시각적으로 밀어 넣을 수 있는 오프셋 클래스를 생성해야 합니다. 또 다시 수학을!</p> + +<p>이렇게 해봅시다.</p> + +<p>이전 코드에서 출발하거나, <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/grids/fluid-grid.html">fluid-grid.html</a>을 착수 파일로 사용합니다.</p> + +<p>컨테이너 요소를 한 열 너비만큼 밀어낼 클래스를 여러분의 씨에스에스 안에 생성합니다. 다음을 당신의 씨에스에스의 맨 아래에 추가하세요:</p> + +<pre class="brush: css">.offset-by-one { + margin-left: calc(6.25% + (2.08333333%*2)); +}</pre> + +<p>Or if you prefer to calculate the percentages yourself, use this one:</p> + +<pre class="brush: css">.offset-by-one { + margin-left: 10.41666666%; +}</pre> + +<p>이제 여러분이 왼편에 하나의 열 너비의 빈 공간을 남기길 원하는 컨테이너는 어느 것이든 이 클래스를 추가할 수 있습니다. 예를 들면 여러분의 에이치티엠엘에 이런 내용이 있다면:</p> + +<pre class="brush: html"><div class="col span6">14</div></pre> + +<p>그걸 다음으로 대체하세요.</p> + +<pre class="brush: html"><div class="col span5 offset-by-one">14</div></pre> + +<div class="note"> +<p><strong>참고</strong>: 간격띄우기를 위한 공간을 만들기 위해, 합쳐질 열의 갯수를 줄여야 한다는 걸 놓치지 마세요!</p> +</div> + +<p>달라진 모습을 보려면 브라우저에 불러들이거나 새로고침을 하세요. 아니면 <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/grids/fluid-grid-offset.html">fluid-grid-offset.html</a> 예제가 <a href="http://mdn.github.io/learning-area/css/css-layout/grids/fluid-grid-offset.html">실제 실행</a>되는 장면을 보세요. 완성된 예는 다음과 같이 보여야 합니다.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13903/offset-grid-finished.png" style="display: block; height: 47px; margin: 0px auto; width: 944px;"></p> + +<div class="note"> +<p><strong>참고</strong>: 추가 연습의 하나로 여러분은 <code>offset-by-two</code>(2칸 간격띄우기) 클래스를 구현할 수 있습니가?</p> +</div> + +<h3 id="부동_격자_제한">부동 격자 제한</h3> + +<p>이런 시스템을 사용할 때는 총 너비가 정확하게 합산되는지, 행이 수용할 수 있는 것보다 더 많은 열을 하나로 합치려는 요소 무리를 행에 포함하지 않도록 주의해야 합니다. 부동체가 작동하는 방식 때문에 격자 열의 갯수가 해당 격자에 비해 너무 과대해지면 끝 부분에 있는 요소 무리가 다음 행으로 떨어지면서 격자가 깨집니다.</p> + +<p>또한 요소 무리의 콘텐츠가 그들 요소들이 점유하는 행보다 넓어지면, 대열이탈되어 엉망으로 보일 것이라는 점을 염두에 두십시오.</p> + +<p>이 시스템의 가장 큰 한계는 본질적으로 1차원이라는 점에 있습니다. 우리가 지금 여러 열에 걸쳐 요소를 하나로 합치도록 처리하자는 것이지 행 처리가 아닙니다. 이러한 오래된 조판 메서드는 요소의 높이를 명시적으로 설정하지 않고서는 요소의 높이를 제어하기가 매우 어렵습니다. 이는 매우 유연하지 않은 접근 방식이기도 합니다. 이는 여러분의 콘텐츠가 특정 높이라고 예상될 경우에만 먹힙니다.</p> + +<h2 id="가변상자_격자">가변상자 격자?</h2> + +<p><a href="/ko/docs/Learn/CSS/CSS_layout/Flexbox">가변상자</a>에 대한 이전 기사를 읽으면 가변상자가 격자 시스템을 생성하는 데 이상적인 해결책이라고 생각할 수 있습니다. 이용할 수 있는 가변상자 기반 격자 시스템이 많이 있으며, 가변상자는 상기한 내용에서 격자를 만들 때 이미 발견한 많은 문제를 해결할 수 있습니다.</p> + +<p>그러나 가변상자는 격자 시스템처럼 디자인되지 않았으며 그런 식의 시스템으로 사용할 때 일련의 새로운 도전 과제를 던져줍니다. 간단한 예로 위에서 사용한 것과 동일한 예제 마크업을 채택해 아래의 씨에스에스를 사용하여 <code>wrapper</code>와 <code>row</code> 및 <code>col</code> 클래스를 사용하여 스타일링할 수 있습니다.</p> + +<pre class="brush: css">body { + width: 90%; + max-width: 980px; + margin: 0 auto; +} + +.wrapper { + padding-right: 2.08333333%; +} + + +.row { + display: flex; +} + +.col { + margin-left: 2.08333333%; + margin-bottom: 1em; + width: 6.25%; + flex: 1 1 auto; + background: rgb(255,150,150); +}</pre> + +<p>이 대체 요소를 여러분의 예제에서 만들거나, 우리의 <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/grids/flexbox-grid.html">flexbox-grid.html</a> 예제 코드를 볼 수 있습니다(<a href="http://mdn.github.io/learning-area/css/css-layout/grids/flexbox-grid.html">실제 실행</a> 장면도 참조하세요).</p> + +<p>여기에서 우리는 각 행을 가변 컨테이너로 탈바꿈하고 있습니다. 가변상자 기반 격자가 있다고 하더라도 요소를 다합쳐 100% 미만를 차지하는 요소 무리를 확보하려면 여러분은 여전히 행이 필요합니다. 우리는 해당 콘테이너를 <code>display: flex</code>로 설정했습니다.</p> + +<p>우리는 <code>.col</code> 클래스상에 {{cssxref("flex")}} 속성의 첫 번째 값인 ({{cssxref("flex-grow")}})를 1로 설정하여 항목 무리가 확장할 수 있게 하고, 두 번째 속성값인 ({{cssxref("flex-shrink")}})를 1로 설정하여 항목 무리가 축소할 수 있게 하며 세 번째 값인 ({{cssxref("flex-basis")}})를 <code>auto</code>로 설정했습니다. 우리의 요소는 {{cssxref("width")}}(너비)가 설정되어 있고, <code>auto</code> 값을 통해 해당 너비값을 <code>flex-basis</code> 값으로 사용하게 됩니다.</p> + +<p>맨 위 라인에는 격자 위에 12개의 깔끔한 상자가 있고, 뷰포트 너비를 변경할 때 상자는 똑같이 확장하고 수축합니다. 그러나 다음 행에서는 4개의 항목만 있으며, 이들은 60px 기준에서 확장하고 축소됩니다. 그 중 단 4개만 상위 행에 있는 항목보다 훨씬 더 많이 확장할 수 있습니다. 그 결과 두 번째 행에서 모두 같은 너비를 차지합니다.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13905/flexbox-grid-incomplete.png" style="display: block; height: 71px; margin: 0px auto; width: 944px;"></p> + +<p>이를 수정하려면 해당 요소에 대해 <code>flex-basis</code>가 사용하는 값을 대체할 너비를 제공하기 위해 <code>span</code> 클래스를 포함해야 합니다.</p> + +<p>또한 상위 항목 무리가 사용하는 격자를 존중하지 않습니다. 왜냐하면 그들은 그것에 대해 아무것도 모르기 때문입니다.</p> + +<p>가변상자는 디자인 자체로 <strong>one-dimensional</strong>입니다. 그것은 1차원 즉 행이나 열을 다룹니다. 열과 행에 대해 엄격한 격자를 만들 수는 없습니다. 즉, 여러분의 격자에 가변상자를 사용하려면 부동 조판에서와 같이 백분율을 계산해야 합니다.</p> + +<p>당신이 참여하는 프로젝트에서 부동체보다 가변상자가 제공하는 공간 배분 능력이나 추가적인 정렬 기능을 이유로 여전히 가변상자 '격자'를 선택해 사용할 수도 있습니다. 하지만 당신이 사용하는 것이 원래 설계된 목적 이외의 다른 목적의 도구를 사용하고 있다는 것을 알아야 합니다. 그래서 당신은 이런 느낌이 들지도 모르겠다. 내가 원하는 최종 결과를 얻으려는 나에게 이놈이 추가적인 장애물을 통과하도록 만들고 있구나.</p> + +<h2 id="제3자_격자_시스템">제3자 격자 시스템</h2> + +<p>이제 우리는 격자 셈법의 배경이 되는 수학을 이해하게 되면서, 널리 이용되고 있는 제3자 격자 시스템 중 일부를 살펴 볼만한 좋은 여건을 갖췄습니다. 웹에서 "씨에스에스 격자 프레임워크"를 검색하면 선택할 수 있는 옵션 목록이 엄청납니다. <a href="http://getbootstrap.com/">Bootstrap</a>와 <a href="http://foundation.zurb.com/">Foundation</a>같은 인기 프레임워크에는 격자 시스템이 포함되어 있습니다. 또한 씨에스에스 혹은 전처리기를 사용하여 개발된 독립형 격자 시스템도 있습니다.</p> + +<p>이 독립형 시스템 중 하나를 살펴봅니다. 이 시스템은 격자 프레임워크를 사용하는 일반적인 기술을 보여줍니다. 우리가 사용할 격자는 단순한 씨에스에스 프레임워크인 Skeleton의 일부입니다.</p> + +<p>시작하려면 <a href="http://getskeleton.com/">Skeleton website</a>를 방문하고 ZIP 파일을 다운로드하기 위해 "다운로드"를 선택합니다. 압축파일을 풀고 skeleton.css와 normalize.css를 새 폴더에 복사하십시요.</p> + +<p><a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/grids/html-skeleton.html">html-skeleton.html</a>파일의 복사본을 만들어, skeleton과 normalize 씨에스에스 파일이 위치한 폴더와 같은 폴더에 저장합니다.</p> + +<p>다음과 같은 내용을 복사본 파일의 헤드 섹션에 skeleton과 normalize 씨에스에스 파일에 포함시킵니다:</p> + +<pre class="brush: html"><link href="normalize.css" rel="stylesheet"> +<link href="skeleton.css" rel="stylesheet"></pre> + +<p>Skeleton에는 격자 시스템 이외에도 많은 내용이 포함되어 있습니다. 타이포그래피를 위한 씨에스에스 및 착수점으로 사용할 수 있는 다른 페이지 요소도 포함되어 있습니다. 하지만 지금은 이들을 기본값으로 남겨둘 겁이다. 우리가 정말로 관심을 갖고 있는 것은 격자입니다.</p> + +<div class="note"> +<p><strong>참고</strong>: <a href="/en-US/docs/">Normalize</a>는 니콜라스 겔러거가 작성한 정말로 유용한 소형 씨에스에스 라이브러리로, 자동으로 몇 가지 유용한 기본 조판의 수정을 수행하고, 기본 요소 스타일링을 브라우저를 막론하고 보다 일관되게 만들어 줍니다.</p> +</div> + +<p>우리는 이전 예와 비슷한 에이치티엠엘을 사용할 것입니다. 다음을 여려분의 에이치티엠엘 바디에 추가하십시요:</p> + +<pre class="brush: html"><div class="container"> + <div class="row"> + <div class="col">1</div> + <div class="col">2</div> + <div class="col">3</div> + <div class="col">4</div> + <div class="col">5</div> + <div class="col">6</div> + <div class="col">7</div> + <div class="col">8</div> + <div class="col">9</div> + <div class="col">10</div> + <div class="col">11</div> + <div class="col">12</div> + </div> + <div class="row"> + <div class="col">13</div> + <div class="col">14</div> + <div class="col">15</div> + <div class="col">16</div> + </div> +</div></pre> + +<p><br> + Skeleton을 사용하기 위해서는 <code>container</code> 클래스를 랩퍼(바깥쪽) {{htmlelement("div")}}에 부여할 필요가 있습니다. 이 내용은 이미 우리 에이치티엠엘에 포함되어 있습니다. 이것은 최대 너비가 960픽셀인 콘텐츠를 중심부에 위치시킵니다. 이제 상자의 너비가 어떻게 960픽셀을 절대 초과할 수 없는지 볼 수 있습니다.</p> + +<p>이 클래스를 적용할 때 사용되는 씨에스에스를 보려면 skeleton.css 파일을 직접 볼 수 있습니다. <code><div></code>는 <code>auto</code> 좌우 여백 을 사용하여 중심부 위치에 놓이고, 20픽셀의 패딩을 좌우로 적용한다. 또한 Skeleton은 {{cssxref("box-sizing")}} 속성을 우리가 이전에 했던 것처럼 <code>border-box</code>로 설정하므로 이 요소의 패딩과 경계가 전체 너비에 포함됩니다.</p> + +<pre class="brush: css">.container { + position: relative; + width: 100%; + max-width: 960px; + margin: 0 auto; + padding: 0 20px; + box-sizing: border-box; +}</pre> + +<p>요소는 행 안에 있는 경우에만 격자의 일부가 될 수 있으므로, 이전 예제와 마찬가지로 추가적인 <code><div></code>가 필요하거나 <code>content</code>와 <code><div></code>, 실제 콘텐츠 컨테이너 <code><div></code> 무리 사이에 중첩된 <code>row</code> 클래스가 부여된 다른 요소가 필요합니다. 우리는 이미 이것을 완성했습니다.</p> + +<p>이제 컨테이너 상자를 정리해 봅시다. Skeleton은 12개의 열 격자 기반입니다. 맨 위 라인의 상자 전체는 그 상자 무리를 하나의 열로 합치기 위해 모두 <code>one column</code>이란 클래스가 필요합니다.</p> + +<p>아래에 나온 에이치티엠엘 조각 내용을 지금 추가하십시오.</p> + +<pre class="brush: html"><div class="container"> + <div class="row"> + <div class="one column">1</div> + <div class="one column">2</div> + <div class="one column">3</div> + /* and so on */ + </div> +</div></pre> + +<p>다음으로 아래와 같이 하나로 합치기할 열의 수를 설명하는 클래스를 두 번째 행에 놓인 컨테이너에 부여합니다.</p> + +<pre class="brush: html"><div class="row"> + <div class="one column">13</div> + <div class="six columns">14</div> + <div class="three columns">15</div> + <div class="two columns">16</div> +</div></pre> + +<p>에이치티엠엘 파일을 저장하고 브라우저에 불러들여 효과를 확인하십시오.</p> + +<div class="note"> +<p><strong>참고</strong>:위의 예제를 제대로 적용하기가 어렵다면, 그것을 우리의 <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/grids/html-skeleton-finished.html">html-skeleton-finished.html</a> 파일과 비교해 보십시요. (그것을 <a href="http://mdn.github.io/learning-area/css/css-layout/grids/html-skeleton-finished.html">라이브로도 보세요</a>).</p> +</div> + +<p>당신이 (앞서 다운로드한) skeleton.css 내용을 보면 어떻게 작동하는지 알 수 있습니다. 예를 들어, Skeleton 파일에는 다음과 같이 "three columns" 클래스가 적용되는 요소를 스타일링하기 위한 정의가 부여되어 있습니다.</p> + +<pre class="brush: css">.three.columns { width: 22%; }</pre> + +<p>모든 Skeleton(또는 다른 격자 프레임워크)은 여러분의 마크업에 추가하여 사용할 수 있는 미리 정의된 클래스를 설정하는 것입니다. 해당 백분율을 계산하는 작업은 마치 당신이 직접 한 것과 똑같습니다.</p> + +<p>보시다시피, 우리는 Skeleton을 사용할 때 씨에스에스를 거의 쓰지 않아도 됩니다. 그것은(Skeleton) 당신의 마크업에 클래스를 추가할 때 우리를 대신해 모든 부동 요소를 처리합니다. 격자 시스템에 대한 프레임워크를 사용하여 만들어진 무언가에 조판에 대한 책임을 넘겨주는 이러한 능력을 갖춘 Skeleton은 설득력있는 선택입니다. 그러나 요즘 씨에스에스 격자 조판도 있고해서 많은 개발자가 씨에스에스가 제공하는 내장형 고유 격자를 사용하기 위해 이러한 프레임 워크에서 멀어지고 있습니다.</p> + +<h2 id="요약정리">요약정리</h2> + +<p>이제 다양한 격자 시스템이 어떻게 만들어지는지 이해하게 되었는데, 이는 구형 사이트에서 작업할 때와 씨에스에스 격자 조판이 제공하는 기본 격자와 이들 구형 시스템 간의 차이를 이해하는 데 유용합니다.</p> + +<p>{{PreviousMenuNext("Learn/CSS/CSS_layout/Media_queries", "Learn/CSS/CSS_layout/Supporting_Older_Browsers", "Learn/CSS/CSS_layout")}}</p> + +<h2 id="이번_단위에는">이번 단위에는</h2> + +<ul> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Introduction">씨에스에스 조판 소개</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/일반_흐름">일반 대열</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Flexbox">가변상자</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Grids">격자</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Floats">부동체</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/위치잡기">위치잡기</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Multiple-column_Layout">다단 조판</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/반응형_디자인">반응형 디자인</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/미디어_쿼리_초보자_안내서">미디어 쿼리 초보자 안내서</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Legacy_Layout_Methods">레거시 조판 메서드</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/%EC%9D%B4%EC%A0%84_%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80_%EC%A7%80%EC%9B%90">이전 브라우저 지원</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Fundamental_Layout_Comprehension">조판 이해도 필수 평가</a></li> +</ul> diff --git a/files/ko/learn/css/css_layout/multiple-column_layout/index.html b/files/ko/learn/css/css_layout/multiple-column_layout/index.html new file mode 100644 index 0000000000..70f13c6c39 --- /dev/null +++ b/files/ko/learn/css/css_layout/multiple-column_layout/index.html @@ -0,0 +1,415 @@ +--- +title: 다단 레이아웃 +slug: Learn/CSS/CSS_layout/Multiple-column_Layout +tags: + - CSS 붕괴 + - 다단 + - 다단 레이아웃 + - 안내서 + - 초보자 + - 학습 +translation_of: Learn/CSS/CSS_layout/Multiple-column_Layout +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/CSS/CSS_layout/Positioning", "Learn/CSS/CSS_layout/Responsive_Design", "Learn/CSS/CSS_layout")}}</div> + +<p class="summary">CSS 다단 레이아웃 규격은 신문에서 볼 수 있듯이 콘텐츠를 단으로 배치하는 방법을 제공합니다. 이 문서는 그 기능을 어떻게 사용하는지 설명합니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">선결 사항:</th> + <td>HTML의 기초 (<a href="/ko/docs/Learn/HTML/Introduction_to_HTML">HTML 입문서</a>)와 CSS 작동 방식에 대한 개념(<a href="/en-US/docs/Learn/CSS/Introduction_to_CSS">CSS 입문서</a>를 공부하세요.)</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>신문에서 찾을 수 있는 것과 같은 웹 페이지상에 다단 레이아웃을 만드는 방법을 학습합니다.</td> + </tr> + </tbody> +</table> + +<h2 id="기본_사례">기본 사례</h2> + +<p>이제 다단 레이아웃을 사용하는 방법을 탐색할 것입니다. 이를 일컬어 <em>multicol</em>(다단)로 통칭합니다. 아래 내용을 따라하려면 <a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/multicol/0-starting-point.html">다단 착수 파일</a>을 다운로드하고 적절한 장소에 CSS를 추가할 수 있습니다. 해당 섹션의 맨 아래에는 최종 코드가 어떻게 생겼는지에 대한 실제 예제가 있습니다.</p> + +<p>우리의 착수 파일에는 아주 간단한 HTML이 포함되어 있습니다. 그 내용은 제목과 일부 단락이 내부에 있는 <code>container</code> 클래스 래퍼입니다.</p> + +<p>컨테이너 클래스에 해당하는 {{htmlelement("div")}}는 다단 컨테이너가 될 예정입니다. {{cssxref("column-count")}} 혹은 {{cssxref("column-width")}} 속성 중의 하나를 사용해서 다단으로 전환합니다. <code>column-count</code> 속성은 당신이 부여하는 값만큼 다단을 생성하게 되며, 당신의 스타일시트에 다음과 같은 CSS를 추가하고 페이지를 새로고침하면 당신은 삼단 레이아웃을 얻게 됩니다:</p> + +<pre class="brush: css">.container { + column-count: 3; +} +</pre> + +<p>당신이 생성하는 단은 가변 너비를 갖게됩니다. 말하자면 브라우저가 각 단에 할당한 공간의 크기를 계산합니다.<</p> + +<div id="다단_1"> +<div class="hidden"> +<h6 id="단의_갯수_예제">단의 갯수 예제</h6> + +<pre class="brush: css">body { + width: 90%; + max-width: 900px; + margin: 2em auto; + font: .9em/1.2 Arial, Helvetica, sans-serif; +} + </pre> +</div> + +<pre class="brush: html"><div class="container"> + <h1>간단한 다단 예제</h1> + + <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. + Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. + Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse + ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit + quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p> + + <p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed est. Nam id risus quis ante semper consectetur eget aliquam lorem. Vivamus tristique + elit dolor, sed pretium metus suscipit vel. Mauris ultricies lectus sed lobortis finibus. Vivamus eu urna eget velit + cursus viverra quis vestibulum sem. Aliquam tincidunt eget purus in interdum. Cum sociis natoque penatibus et magnis + dis parturient montes, nascetur ridiculus mus.</p> +</div> +</pre> + +<pre class="brush: css">.container { + column-count: 3; +} +</pre> +</div> + +<p>{{ EmbedLiveSample('다단_1', '100%', 400) }}</p> + +<p>다음과 같이 <code>column-width</code>를 사용하여 당신의 CSS를 변경하세요:</p> + +<pre class="brush: css">.container { + column-width: 200px; +} +</pre> + +<p>이제 브라우저는 당신이 지정한 크기의 단을 최대한 많이 제공합니다. 남은 공간은 현존하는 단 사이 공평하게 배분됩니다. 즉, 컨테이너가 해당 너비로 정확히 나뉠 수 없는 경우를 제외하고는 지정한 너비를 정확히 얻을 수 없습니다.</p> + +<div id="다단_2"> +<div class="hidden"> +<h6 id="단_너비_예제">단 너비 예제</h6> + +<pre class="brush: css">body { + width: 90%; + max-width: 900px; + margin: 2em auto; + font: .9em/1.2 Arial, Helvetica, sans-serif; +}</pre> + +<pre class="brush: html"><div class="container"> + <h1>간단한 다단 예제</h1> + + <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. + Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. + Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse + ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit + quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p> + + <p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed est. Nam id risus quis ante semper consectetur eget aliquam lorem. Vivamus tristique + elit dolor, sed pretium metus suscipit vel. Mauris ultricies lectus sed lobortis finibus. Vivamus eu urna eget velit + cursus viverra quis vestibulum sem. Aliquam tincidunt eget purus in interdum. Cum sociis natoque penatibus et magnis + dis parturient montes, nascetur ridiculus mus.</p> +</div></pre> +</div> + +<pre class="brush: css">.container { + column-width: 200px; +} +</pre> +</div> + +<p>{{ EmbedLiveSample('다단_2', '100%', 400) }}</p> + +<h2 id="다단_스타일링">다단 스타일링</h2> + +<p>다단으로 작성된 단은 개별적으로 스타일링할 수 없습니다. 하나의 단을 다른 단보다 크게 만들거나 단일 단의 배경 또는 텍스트 색상을 변경할 수 있는 방법이 없습니다. 단이 표시되는 방식을 바꿀 수 있는 기회는 두 가지가 주어집니다.</p> + +<ul> + <li>{{cssxref("column-gap")}}를 사용해 다단 사이 간격의 크리를 변경하기.</li> + <li>{{cssxref("column-rule")}}를 가지고 다단 사이 규칙을 추가하기.</li> +</ul> + +<p>상기 예제 용례에서 <code>column-gap</code> 속성을 추가해 간격의 크기를 변경하세요:</p> + +<pre class="brush: css">.container { + column-width: 200px; + column-gap: 20px; +}</pre> + +<p>서로 다른 값을 가지고 마음대로 부릴 수 있습니다. 모든 길이 단위를 속성이 허용한다는 말입니다. 이제 <code>column-rule</code>를 가지고 다단 사이 규칙을 추가하세요. 이전 단원에서 접했던 {{cssxref("border")}} 속성과 비슷한 방식으로 <code>column-rule</code>는 {{cssxref("column-rule-color")}}와 {{cssxref("column-rule-style")}} {{cssxref("column-rule-width")}}의 약칭이며 <code>border</code>와 동일한 값을 허용합니다.</p> + +<pre class="brush: css">.container { + column-count: 3; + column-gap: 20px; + column-rule: 4px dotted rgb(79, 185, 227); +}</pre> + +<p>다른 스타일과 색상 규칙을 추가하세요</p> + +<div id="다단_3"> +<div class="hidden"> +<h6 id="다단_스타일링_2">다단 스타일링</h6> + +<pre class="brush: css">body { + width: 90%; + max-width: 900px; + margin: 2em auto; + font: .9em/1.2 Arial, Helvetica, sans-serif; +} +.container { + column-count: 3; + column-gap: 20px; + column-rule: 4px dotted rgb(79, 185, 227); +}</pre> + +<pre class="brush: html"><div class="container"> + <h1>간단한 다단 예제</h1> + + <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. + Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. + Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse + ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit + quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p> + + <p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed est. Nam id risus quis ante semper consectetur eget aliquam lorem. Vivamus tristique + elit dolor, sed pretium metus suscipit vel. Mauris ultricies lectus sed lobortis finibus. Vivamus eu urna eget velit + cursus viverra quis vestibulum sem. Aliquam tincidunt eget purus in interdum. Cum sociis natoque penatibus et magnis + dis parturient montes, nascetur ridiculus mus.</p> +</div></pre> +</div> +</div> + +<p>{{ EmbedLiveSample('다단_3', '100%', 400) }}</p> + +<p>주목할 점은 규칙이 자체적으로 폭을 점유하지 않는다는 것입니다. 규칙이 적용된 내용은 당신이 <code>column-gap</code>으로 생성된 간격을 가로질러 놓여 있습니다. 규칙을 따라 양쪽에 더 많은 공간을 만들려면 <code>column-gap</code> 크기를 늘려야 합니다.</p> + +<h2 id="Spanning_columns">Spanning columns</h2> + +<p>다단 레이아웃에 의해 콘텐츠가 span across 됩니다. 그것은 본질적으로 페이지 미디어상에 콘텐츠가 작동하는 것과 같은 방식으로 작동합니다. 예를 들면 웹페이지 인쇄가 그렇습니다. 콘텐츠를 다단 컨테이너로 만들면 다단으로 나눠지고, 그것이 가능해진 결과로 콘텐츠는 깨집니다.</p> + +<p>때때로, 이런 깨짐 현상은 발생하는 위치에 따라 독서를 저해하는 경험을 낳을 것입니다. 아래의 실제 사용례에서 나는 다단을 사용하여 일련의 상자를 배치했는데, 각각에는 머리글과 약간의 텍스트가 들어 있습니다. 다단 사이가 단편화할 경우 제목은 텍스트와 분리됩니다.</p> + +<div id="다단_4"> +<div class="hidden"> +<h6 id="카드_용례">카드 용례</h6> + +<pre class="brush: css">body { + width: 90%; + max-width: 900px; + margin: 2em auto; + font: .9em/1.2 Arial, Helvetica, sans-serif; +} </pre> +</div> + +<pre class="brush: html"><div class="container"> + <div class="card"> + <h2>나는 머리글이다.</h2> + <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat + vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies + tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci + vel, viverra egestas ligula.</p> + </div> + + <div class="card"> + <h2>나는 머리글이다.</h2> + <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat + vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies + tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci + vel, viverra egestas ligula.</p> + </div> + + <div class="card"> + <h2>나는 머리글이다.</h2> + <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat + vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies + tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci + vel, viverra egestas ligula.</p> + </div> + <div class="card"> + <h2>나는 머리글이다.</h2> + <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat + vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies + tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci + vel, viverra egestas ligula.</p> + </div> + + <div class="card"> + <h2>나는 머리글이다.</h2> + <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat + vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies + tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci + vel, viverra egestas ligula.</p> + </div> + + <div class="card"> + <h2>나는 머리글이다.</h2> + <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat + vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies + tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci + vel, viverra egestas ligula.</p> + </div> + + <div class="card"> + <h2>나는 머리글이다.</h2> + <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat + vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies + tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci + vel, viverra egestas ligula.</p> + </div> + +</div> +</pre> + +<pre class="brush: css">.container { + column-width: 250px; + column-gap: 20px; +} + +.card { + background-color: rgb(207, 232, 220); + border: 2px solid rgb(79, 185, 227); + padding: 10px; + margin: 0 0 1em 0; +}</pre> +</div> + +<p>{{ EmbedLiveSample('다단_4', '100%', 600) }}</p> + +<p>이러한 동작을 제어하기 위해 <a href="/en-US/docs/Web/CSS/CSS_Fragmentation">CSS 붕괴</a> 규격에 있는 속성을 사용할 수 있습니다. 우리는 이 규격에 있는 속성을 통해 다단과 페이지 미디어에 포함된 콘텐츠가 깨지는 것을 제어할 수 있습니다. 예를 들어, <code>.card</code> 클래스에 대한 규칙에 <code>avoid</code> 값을 사용한 {{cssxref("break-inside")}}을 추가하세요. 이것은 머리글과 텍스트로 구성된 컨테이너입니다. 따라서 우리는 이 상자를 분열하고 싶지 않습니다.</p> + +<p>현 시점에 이전 속성인 <code>page-break-inside: avoid</code>을 최상의 브라우저 지원을 위해 추가할 가치가 있습니다.</p> + +<pre class="brush: css">.card { + break-inside: avoid; + page-break-inside: avoid; + background-color: rgb(207,232,220); + border: 2px solid rgb(79,185,227); + padding: 10px; + margin: 0 0 1em 0; +} +</pre> + +<p>페이지를 새로고침하면 상자가 하나의 형태를 갖추고 있어야 합니다.</p> + +<div id="다단_5"> +<div class="hidden"> +<h6 id="다단_단편">다단 단편</h6> + +<pre class="brush: css">body { + width: 90%; + max-width: 900px; + margin: 2em auto; + font: .9em/1.2 Arial, Helvetica, sans-serif; +} </pre> + +<pre class="brush: html"><div class="container"> + <div class="card"> + <h2>나는 머리글이다.</h2> + <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat + vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies + tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci + vel, viverra egestas ligula.</p> + </div> + + <div class="card"> + <h2>나는 머리글이다.</h2> + <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat + vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies + tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci + vel, viverra egestas ligula.</p> + </div> + + <div class="card"> + <h2>나는 머리글이다.</h2> + <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat + vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies + tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci + vel, viverra egestas ligula.</p> + </div> + <div class="card"> + <h2>나는 머리글이다.</h2> + <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat + vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies + tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci + vel, viverra egestas ligula.</p> + </div> + + <div class="card"> + <h2>나는 머리글이다.</h2> + <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat + vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies + tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci + vel, viverra egestas ligula.</p> + </div> + + <div class="card"> + <h2>나는 머리글이다.</h2> + <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat + vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies + tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci + vel, viverra egestas ligula.</p> + </div> + + <div class="card"> + <h2>나는 머리글이다.</h2> + <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat + vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies + tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci + vel, viverra egestas ligula.</p> + </div> + +</div> +</pre> +</div> + +<pre class="brush: css">.container { + column-width: 250px; + column-gap: 20px; +} + +.card { + break-inside: avoid; + page-break-inside: avoid; + background-color: rgb(207, 232, 220); + border: 2px solid rgb(79, 185, 227); + padding: 10px; + margin: 0 0 1em 0; +}</pre> +</div> + +<p>{{ EmbedLiveSample('다단_5', '100%', 600) }}</p> + +<h2 id="요약정리">요약정리</h2> + +<p>이제 당신이 현재 설계 중인 레이아웃 메서드를 선택할 때 맘껏 사용할 수 있는 다단 레이아웃의 기본 기능과 다른 도구를 사용하는 방법을 알게 되었습니다.</p> + +<h2 id="참조_항목">참조 항목</h2> + +<ul> + <li><a href="/kr/docs/Web/CSS/CSS_Fragmentation">CSS 붕괴</a></li> + <li><a href="/kr/docs/Web/CSS/CSS_Columns/Using_multi-column_layouts">다단 레이아웃 사용하기</a></li> +</ul> + +<p>{{PreviousMenuNext("Learn/CSS/CSS_layout/Positioning", "Learn/CSS/CSS_layout/Responsive_Design", "Learn/CSS/CSS_layout")}}</p> + +<h2 id="이번_단위에는">이번 단위에는</h2> + +<ul> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Introduction">CSS 레이아웃 소개</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/일반_흐름">일반 대열</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Flexbox">flexbox</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Grids">그리드</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Floats">Floats</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/위치잡기">위치잡기</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Multiple-column_Layout">다단 레이아웃</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/반응형_디자인">반응형 디자인</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/미디어_쿼리_초보자_안내서">미디어 쿼리 초보자 안내서</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/레거시_조판_메서드">레거시 레이아웃 메서드</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/%EC%9D%B4%EC%A0%84_%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80_%EC%A7%80%EC%9B%90">이전 브라우저 지원</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Fundamental_Layout_Comprehension">레이아웃 이해도 필수 평가</a></li> +</ul> diff --git a/files/ko/learn/css/css_layout/미디어_쿼리_초보자_안내서/index.html b/files/ko/learn/css/css_layout/미디어_쿼리_초보자_안내서/index.html new file mode 100644 index 0000000000..cf13a1421c --- /dev/null +++ b/files/ko/learn/css/css_layout/미디어_쿼리_초보자_안내서/index.html @@ -0,0 +1,424 @@ +--- +title: 미디어 쿼리 초보자 안내서 +slug: Learn/CSS/CSS_layout/미디어_쿼리_초보자_안내서 +tags: + - 미디어 쿼리 + - 씨에스에스 + - 조판 + - 초보자 + - 학습 +translation_of: Learn/CSS/CSS_layout/Media_queries +--- +<p>{{learnsidebar}}{{PreviousMenuNext("Learn/CSS/CSS_layout/Responsive_Design", "Learn/CSS/CSS_layout/Legacy_Layout_Methods", "Learn/CSS/CSS_layout")}}</p> + +<p><strong>CSS Media Query</strong>는 예를 들어 "뷰포트가 480 픽셀보다 넓다."라고 여러분이 지정한 규칙에 브라우저 및 장치 환경이 일치하는 경우에만 씨에스에스를 적용할 수 있는 방법을 제공합니다. 미디어 쿼리는 반응형 웹 디자인의 핵심 부분이다. 뷰포트의 크기에 따라 서로 다른 조판을 생성할 수 있기 때문이다. 그러나 예를들면 사용자는 마우스가 아닌 터치스크린을 사용하는지와 같이 실행 중인 사이트 환경에 대한 여러 내용들을 탐지하는 데도 사용할 수 있습니다. 이번 단원에서는 먼저 미디어 쿼리에 사용된 구문에 대해 배우고, 이어 해당 구문을 가공의 예제에서 사용하여 간단한 디자인이 어떻게 반응할 수 있는지 살펴보겠습니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">선결 사항:</th> + <td>에이치티엠엘의 기초인 (<a href="/ko/docs/Learn/HTML/Introduction_to_HTML">에이치티엠엘 입문서</a>를 공부하세요), 그리고 씨에스에스의 작동 방식을 파악하기 위해 (<a href="/en-US/docs/Learn/CSS/First_steps">씨에스에스 첫걸음</a>과 <a href="/ko/docs/Learn/CSS/Building_blocks">씨에스에스 구성 블록</a>를 공부하세요.)</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>미디어 쿼리를 사용하는 방법과 그걸 이용해 반응형 디자인을 생성하기 위한 가장 대표적인 접근법 파악하기.</td> + </tr> + </tbody> +</table> + +<h2 id="미디어_쿼리_기본">미디어 쿼리 기본</h2> + +<p>가장 간단한 미디어 쿼리 구문은 다음과 같습니다:</p> + +<pre class="brush: css">@media <em>media-type</em> and (<em>media-feature-rule</em>) { + /* CSS rules go here */ +}</pre> + +<p>미디어 쿼리 구문의 구성 요소:</p> + +<ul> + <li>여기 코드가 어떤 미디어를 위한 것인지 브라우저에 알려주는 미디어 유형(예를 들어, 인쇄 또는 화면).</li> + <li>괄호로 묶은 씨에스에스 규칙이 적용되기 위해 전달되어야 하는 규칙 또는 조건문 격인 미디어 표현식.</li> + <li>조건문을 통과하고 미디어 유형이 올바른 경우 적용되는 씨에스에스 규칙 집합.</li> +</ul> + +<h3 id="미디어_유형">미디어 유형</h3> + +<p>당신이 지정할 수 있는 미디어 유형</p> + +<ul> + <li><code>all</code></li> + <li><code>print</code></li> + <li><code>screen</code></li> + <li><code>speech</code></li> +</ul> + +<p>다음 미디어 쿼리는 페이지가 인쇄된 경우에만 본문을 12pt로 설정합니다. 페이지가 브라우저에 로드될 때에는 적용되지 않습니다.</p> + +<pre class="brush: css"><code>@media print { + body { + font-size: 12pt; + } +}</code></pre> + +<div class="blockIndicator note"> +<p><strong>참고</strong>: 수준 3 미디어 쿼리 규격에 정의된 여러 가지 다른 미디어 유형이 있습니다. 이들은 사장되었으니 피해야 합니다.</p> +</div> + +<div class="blockIndicator note"> +<p><strong>참고</strong>: 미디어 유형은 선택사항입니다. 미디어 쿼리에 미디어 유형을 표시하지 않으면 미디어 쿼리는 기본값으로 모든 미디어 유형에 대한 것으로 해석됩니다.</p> +</div> + +<h3 id="미디어_기능_규칙">미디어 기능 규칙</h3> + +<p>미디어 유형을 지정한 뒤에 규칙을 적용할 미디어 기능을 선정할 수 있습니다.</p> + +<h4 id="너비와_높이">너비와 높이</h4> + +<p>반응형 디자인을(그리고 광범위한 브라우저 지원이 되도록) 만들기 위해 가장 자주 탐문하는 기능은 뷰포트 너비이며, <code>min-width</code>와 <code>max-width</code>, <code>width</code> 등의 미디어 기능을 활용하여 뷰포트가 특정 너비 이상 또는 이하인 경우 씨에스에스를 적용할 수 있습니다.</p> + +<p>이러한 특징들은 다른 화면 크기에 반응하는 조판을 생성하는 데 사용됩니다. 예를 들어 뷰포트가 정확히 600픽셀인 경우 본문 색상을 빨간색으로 변경하려면 다음과 같은 미디어 쿼리를 사용합니다.</p> + +<pre class="brush: css"><code>@media screen and (width: 600px) { + body { + color: red; + } +}</code></pre> + +<p><a href="https://mdn.github.io/css-examples/learn/media-queries/width.html">이 예제를</a> 브라우저에서 열거나 <a href="https://github.com/mdn/css-examples/blob/master/learn/media-queries/width.html">소스를 보세요</a>.</p> + +<p><code>width</code>(및 <code>height</code>) 미디어 기능은 범위 지정에 사용될 수 있다. 따라서 <code>min-</code> or <code>max-</code> 접두사를 붙이게 되면 최소값인지 최대값인지 표시할 수 있다. 예를 들어 뷰포트가 400 픽셀보다 좁은 경우 색깔을 파란색으로 만들기 위해 <code>max-width</code>:를 사용할 수 있다.</p> + +<pre class="brush: css"><code>@media screen and (max-width: 400px) { + body { + color: blue; + } +}</code></pre> + +<p><a href="https://mdn.github.io/css-examples/learn/media-queries/max-width.html">이 예제를</a>를 브라우저에서 열거나 <a href="https://github.com/mdn/css-examples/blob/master/learn/media-queries/max-width.html">소스를 보세요</a>.</p> + +<p>실제로 최소값 또는 최대값을 사용하는 것이 반응형 디자인인 경우에 훨씬 유용하므로 <code>width</code> 또는 <code>height</code> 값을 사용하는 경우는 좀처럼 흔치앖습니다.</p> + +<p>미디어 쿼리 규격 수준 4 및 5에 소개된 최신 기능 중 일부가 제한적으로 브라우저 지원이 되지만, 당신이 테스트할 수 있는 다른 여러 미디어 기능이 있습니다. 각 기능은 브라우저 지원 정보와 함께 MDN에 문서화되어 있으니만큼 당신은 <a href="/en-US/docs/Web/CSS/Media_Queries/Using_media_queries#Media_features">미디어 쿼리 사용: 미디어 기능</a>에서 전체 목록을 찾을 수 있습니다.</p> + +<h4 id="방향성">방향성</h4> + +<p>잘 지원되는 미디어 기능 중 하나는 <code>orientation</code>로 세로 모드인지 가로 모드인지를 검사할 수 있도록 해줍니다. 장치가 가로 방향에 있는 경우 본문 텍스트 색상을 변경하려면 다음과 같은 미디어 쿼리를 사용합니다.</p> + +<pre class="brush: css"><code>@media (orientation: landscape) { + body { + color: rebeccapurple; + } +}</code></pre> + +<p><a href="https://mdn.github.io/css-examples/learn/media-queries/orientation.html">이 예제를</a> 브라우저에서 열거나 <a href="https://github.com/mdn/css-examples/blob/master/learn/media-queries/orientation.html">소스를 보세요</a>.</p> + +<p>표준 데스크톱 뷰에는 가로 방향이 주종을 이루고 있으며, 이 가로 방향에서 잘 작동하는 디자인은 휴대폰 또는 태블릿상에서 세로 모드로 볼 때 잘 작동하지 않을 수 있습니다. (가로/세로 모드의) 방향성 테스트는 여러분이 세로 모드의 장치에 최적화된 조판을 생성할 수 있게 도움을 줄 수 있습니다.</p> + +<h4 id="포인팅_장치의_사용">포인팅 장치의 사용</h4> + +<p>수준 4 규격의 일부로 <code>hover</code> 미디어 기능이 도입되었다. 이 기능은 사용자가 요소 위에 (마우스 커서를) 올릴 수 있는 능력을 가진 조건인지를 시험할 수 있다는 것을 의미합니다. 본질적으로 사람들이 어떤 종류의 포인팅 장치를 사용하는지를 말합니다. 터치 스크린 및 키보드 네비게이션은 요소 위에 식별자를 올릴 수 없습니다.</p> + +<pre class="brush: css"><code>@media (hover: hover) { + body { + color: rebeccapurple; + } +}</code></pre> + +<p><a href="https://mdn.github.io/css-examples/learn/media-queries/hover.html">이 예제를</a> 브라우저에서 열거나 <a href="https://github.com/mdn/css-examples/blob/master/learn/media-queries/hover.html">소스를 보세요</a>.</p> + +<p>사용자가 포인팅 장치를 사용할 수 없다고 파악했다면 기본적으로 대화형 기능을 표시할 수 있습니다. 포인팅 장치를 사용할 수 있는 사용자의 경우 링크에 마우스를 올리는 기능을 이용하도록 선택할 수 있습니다.</p> + +<p>마찬가지로 <code>pointer</code> 미디어 기능이 수준 4 규격에 포함되어 있다. 이것은 <code>none</code>과 <code>fine</code> <code>coarse</code>의 세 가지 값을 취할 수 있다. <code>fine</code> 포인터는 마우스나 트랙패드와 같은 것이다. 이 값으로 사용자가 작은 영역을 정확하게 공략할 수 있게 된다. <code>coarse</code> 포인터는 터치스크린상에 손가락을 말한다. <code>none</code> 값은 사용자가 포인팅 장치가 없다는 의미이다. 아마도 키보드 단독 또는 음성 명령으로 탐색하고 있다고 하겠다.</p> + +<p><code>pointer</code> 사용이 당신에게 주는 잇점이 있다면 사용자가 화면상에서 상호 작용하는 유형에 반응하는 더 나은 인터페이스를 설계할 수 있다는 것입니다. 예를 들어, 사용자가 터치스크린으로 장치와 상호 작용하고 있다는 것을 알면 히트 영역을 더 크게 만들 수 있습니다.</p> + +<h2 id="더_복잡한_미디어_쿼리">더 복잡한 미디어 쿼리</h2> + +<p>당신은 가능한 모든 이종의 미디어 쿼리를 가지고 그것들을 결합하거나, 쿼리 목록을 만들고 싶을 수도 있다. 그 중 어느 경우가 (조건문과) 일치할 수 있습니다.</p> + +<h3 id="논리곱_미디어_쿼리">"논리곱" 미디어 쿼리</h3> + +<p><code>and</code>를 사용해 미디어 기능을 결합할 수 있습니다. 이는 마치 앞에서 미디어 유형과 기능을 결합하기 위해 <code>and</code>를 사용했던 방식과 같습니다. 예를 들어, <code>min-width</code>와 <code>orientation</code>의 논리곱 조건을 테스트해보고 싶을 수도 있습니다. 여기서 에이치티엠엘 본문 텍스트가 파란색이 되는 유일한 경우는 뷰포트의 너비가 최소 400픽셀 이상이고 장치가 가로 모드인 경우에만 해당합니다.</p> + +<pre class="brush: css"><code>@media screen and (min-width: 400px) and (orientation: landscape) { + body { + color: blue; + } +}</code></pre> + +<p><a href="https://mdn.github.io/css-examples/learn/media-queries/and.html">이 예제를</a> 브라우저에서 열거나 <a href="https://github.com/mdn/css-examples/blob/master/learn/media-queries/and.html">소스를 보세요</a>.</p> + +<h3 id="논리합_미디어_쿼리">"논리합" 미디어 쿼리</h3> + +<p>만약 여러분에게 쿼리는 잔뜩있는 데, 그 중 일도 일치할 수 없다면, 여러분은 해당 쿼리들을 콤마로 분리할 수 있습니다. 아래 예제에서 뷰포트가 최소 400픽셀 너비 또는 장치가 가로 보기 방향이라면 텍스트는 파란색이 될 것입니다. 둘 중 하나라도 사실이 아니라면 쿼리의 조건문은 일치합니다.</p> + +<pre class="brush: css"><code>@media screen and (min-width: 400px), screen and (orientation: landscape) { + body { + color: blue; + } +}</code></pre> + +<p><a href="https://mdn.github.io/css-examples/learn/media-queries/or.html">이 예제를</a> 브라우저에서 열거나 <a href="https://github.com/mdn/css-examples/blob/master/learn/media-queries/or.html">소스를 보세요</a>.</p> + +<p>"</p> + +<h3 id="부정_논리_미디어_쿼리">"부정 논리" 미디어 쿼리</h3> + +<p><code>not</code> 연산자를 사용하여 전체 미디어 쿼리를 부정할 수 있습니다. 이것은 미디어 쿼리의 전체 의미를 반대로 뒤집습니다. 따라서 다음 예에서 텍스트는 보기 방향이 세로일 경우에만 파란색이 됩니다.</p> + +<pre class="brush: css"><code>@media not all and (orientation: landscape) { + body { + color: blue; + } +}</code></pre> + +<p><a href="https://mdn.github.io/css-examples/learn/media-queries/not.html">이 예제를</a> 브라우저에서 열거나 <a href="https://github.com/mdn/css-examples/blob/master/learn/media-queries/not.html">소스를 보세요</a>.</p> + +<h2 id="분기점을_선정하는_방법">분기점을 선정하는 방법</h2> + +<p>반응형 디자인 초창기에는 많은 디자이너가 매우 구체적인 화면 크기를 공략 대상으로 삼으려고 시도했습니다. 인기있는 휴대폰 및 태블릿 화면의 크기 목록이 공개되어 해당 기기의 뷰포트와 깔끔하게 일치하도록 디자인을 만들 수 있게 되었습니다.</p> + +<p>지금은 엄청나게 다양한 크기의 지나치게 너무 많은 장치가 있어 그런 방식은 현실성이 없습니다. 즉, 모든 디자인마다 (기기의) 특정 크기에 맞추는 공략보다 더 나은 접근 방법은 콘텐츠가 어떤 식으로든 깨지기 시작하는 해당 (기기의) 크기에 해당하는 디자인을 변경하는 것입니다. 어쩌면 선 길이가 너무 길어지거나 상자 형태의 사이드바가 찌그러져 읽기가 어려워질 수도 있습니다. 그 지경이 되면 미디어 쿼리를 사용하여 이용할 수 있는 공간 대비 개선된 형태의 사이트가 나오도록 디자인을 변경해야할 지점인 것입니다. 이는 사용 기기의 정확한 화면 크기가 무엇이든 상관없이 모든 범주에 맞는 전방위적인 접금법을 말합니다. 미디어 쿼리가 도입되는 지점을 <strong>breakpoints</strong>라고 합니다.</p> + +<p>Firefox DevTools의 <a href="/en-US/docs/Tools/Responsive_Design_Mode">반응형 디자인 모드</a>는 이러한 분기점이 어느 부분이 될지 알아내는 데 매우 유용합니다. 동 툴은 미디어 쿼리를 추가하고 디자인을 조정하면서 콘텐츠가 개선되는 위치를 파악하기 위해 뷰포트를 쉽게 크거나 작게 만들 수 있습니다.</p> + +<p><img alt="파이어폭스 개발툴상에 조판 갈무리" src="https://mdn.mozillademos.org/files/16867/rwd-mode.png" style="height: 917px; width: 1443px;"></p> + +<h2 id="능동_학습_모바일_우선_반응형_디자인">능동 학습: 모바일 우선 반응형 디자인</h2> + +<p>대체로 반응형 디자인에 대한 두 가지 접근법을 취할 수 있습니다. 데스크톱 또는 가장 넓은 뷰로 시작한 뒤 뷰포트의 축소에 맞춰 요소를 주변으로 이동시키기 위한 분기점을 추가하거나 가장 작은 뷰로 시작한 뒤에 뷰포트의 크기 확대에 맞춰 조판을 추가할 수 있습니다. 이 두 번째 접근법은 <strong>mobile first</strong> 반응형 디자인으로 설명되며 종종 선호되는 최상의 접근법입니다.</p> + + + +<p>가장 작은 장치용 뷰는 일반 대열에서 나타나는 것처럼 종종 단순한 단일 열 형태의 콘텐츠가 됩니다. 즉 여러분은 작은 장치용이라 많은 조판을 할 필요가 없다는 말입니다. 다시말해 소스를 순서대로 잘 정렬하면 기본값으로 읽을 수 있는 조판이 됩니다.</p> + +<p>아래의 길라잡이는 매우 간단한 조판으로 동 접근 방식을 안내해 줄 것입니다. 사이트 제작 과정에서는 미디어 쿼리내에서 조정할 수 있는 것이 더 많을 수 있지만, 그 접근 방식은 정확히 동일하게 됩니다.</p> + +<h3 id="길라잡이_간단한_모바일_우선_조판">길라잡이: 간단한 모바일 우선 조판</h3> + +<p>우리는 조판에 포함된 다양한 요소에 배경색을 추가하기 위해 일정한 씨에스에스를 적용한 에이치티엠엘 문서를 가지고 출발합니다.</p> + +<pre class="brush: css"><code>* { + box-sizing: border-box; +} + +body { + width: 90%; + margin: 2em auto; + font: 1em/1.3 Arial, Helvetica, sans-serif; +} + +a:link, +a:visited { + color: #333; +} + +nav ul, + aside ul { + list-style: none; + padding: 0; +} + +nav a:link, +nav a:visited { + background-color: rgba(207, 232, 220, 0.2); + border: 2px solid rgb(79, 185, 227); + text-decoration: none; + display: block; + padding: 10px; + color: #333; + font-weight: bold; +} + +nav a:hover { + background-color: rgba(207, 232, 220, 0.7); +} + +.related { + background-color: rgba(79, 185, 227, 0.3); + border: 1px solid rgb(79, 185, 227); + padding: 10px; +} + +.sidebar { + background-color: rgba(207, 232, 220, 0.5); + padding: 10px; +} + +article { + margin-bottom: 1em; +} +</code></pre> + +<p>우리는 우리가 조판에 변경을 가하지는 않았지만, 문서의 원본은 콘텐츠를 읽을 수 있는 방식으로 순서대로 정렬됩니다. 이것은 중요한 첫 번째 단계이며, 콘텐츠가 화면 읽기 프로그램(tts)에 의해 소리내여 읽혀질 경우 콘텐츠가 (읽을 문자열를) 이해될 수도록 보장합니다.</p> + +<pre class="brush: html"><code><body> + <div class="wrapper"> + <header> + <nav> + <ul> + <li><a href="">사이트 소개</a></li> + <li><a href="">연락처</a></li> + <li><a href="">우리팀 안내</a></li> + <li><a href="">블로그</a></li> + </ul> + </nav> + </header> + <main> + <article> + <div class="content"> + <h1>채식주의자!</h1> + <p> + ... + </p> + </aside> + </article> + + <aside class="sidebar"> + <h2>채식에 관한 외부 링크</h2> + <ul> + <li> + ... + </li> + </ul> + </aside> + </main> + + <footer><p>&copy;2019</p></footer> + </div> + </body> +</code></pre> + +<p>이 간단한 조판은 모바일에서도 잘 작동한다. 우리가 파이어폭스 데브툴 내부 반응형 디자인 모드에서 조판을 본다면, 우리는 그것이 사이트의 직관적인 모바일 뷰로 보더라도 꽤 잘 작동한다는 것을 알 수 있다.</p> + +<p><a href="https://mdn.github.io/css-examples/learn/media-queries/step1.html">이 예제를</a> 브라우저에서 열거나 <a href="https://github.com/mdn/css-examples/blob/master/learn/media-queries/step1.html">소스를 보세요</a>.</p> + +<p><strong>당신이 우리의 진행 과정대로 이 예제를 실행해보려면 <a href="https://github.com/mdn/css-examples/blob/master/learn/media-queries/step1.html">step1.html</a>의 사본을 당신 컴퓨터에 만드세요.</strong></p> + +<p>이 지점부터는 반응형 디자인 모드뷰가 점차 확대되어 라인 길이가 상당히 길어지는 모습을 확인할 정도가 되며, 수평선 형태의 탐색 메뉴가 표시될 공간을 갖추고 있습니다. 여기에서 우리는 첫 번째 미디어 쿼리를 추가할 것입니다. 사용자가 텍스트 크기를 늘리게 되면, 텍스트 크기가 작은 장비를 가진 사람과 비교해 비슷한 라인 길이지만 뷰포트가 확대되는 순간에 분기점이 발생한다는 의미입니다. 따라서 우리는 ems 단위를 사용할 것입니다.</p> + +<p><strong>아래 코드를 step1.html 씨에스에스의 하단에 추가하세요.</strong></p> + +<pre class="brush: css"><code>@media screen and (min-width: 40em) { + article { + display: grid; + grid-template-columns: 3fr 1fr; + column-gap: 20px; + } + + nav ul { + display: flex; + } + + nav li { + flex: 1; + } +} +</code></pre> + +<p>이 씨에스에스는 문서 안에 있는 문서 콘텐츠와 aside 요소 내부 관련 정보까지 2단 조판을 우리에게 제공합니다. 또한 우리는 가변상자를 사용하여 탐색 메뉴를 일렬로 배치했습니다.</p> + +<p><a href="https://mdn.github.io/css-examples/learn/media-queries/step2.html">2단계</a> 파일을 브라우저에서 열거나 <a href="https://github.com/mdn/css-examples/blob/master/learn/media-queries/step2.html">소스를 보세요</a>.</p> + +<p>사이드바가 새 단을 형성할 수 있는 충분한 공간이 있다고 느낄 때까지 너비를 계속 확장합니다. 미디어 쿼리안에서 주요 요소를 두 개의 열 형태의 격자로 만들 것입니다. 그런 다음 두 개의 사이드바가 서로 나란히 정렬되도록 문서의 {{cssxref("margin-bottom")}}을 제거해야하며, 바닥글 상단에 {{cssxref("border")}}(테두리)를 추가하게 됩니다. 일반적으로 이러한 미세 조정은 각 분기점 도달시 디자인을 좋게 보이게 하기 위해 여러분이 할 일입니다.</p> + +<p><strong>다시 한 번 아래 코드를 step1.html 씨에스에스의 하단에 추가합니다.</strong></p> + +<pre class="brush: css"><code>@media screen and (min-width: 70em) { + main { + display: grid; + grid-template-columns: 3fr 1fr; + column-gap: 20px; + } + + article { + margin-bottom: 0; + } + + footer { + border-top: 1px solid #ccc; + margin-top: 2em; + } +}</code> +</pre> + +<p><a href="https://mdn.github.io/css-examples/learn/media-queries/step3.html">3단계</a> 파일을 브라우저에서 열거나 <a href="https://github.com/mdn/css-examples/blob/master/learn/media-queries/step3.html">소스를 보세요</a>.</p> + +<p>최종 예제를 다른 너비로 보면 사용 가능한 너비에 따라 디자인이 반응하고 단일 열, 2열 또는 3열로 작동하는 방법을 볼 수 있습니다. 이것은 모바일 우선 반응형 디자인의 아주 간단한 예입니다.</p> + +<h2 id="당신에게_정말_미디어_쿼리가_필요할까요">당신에게 정말 미디어 쿼리가 필요할까요?</h2> + +<p>가변상자, 격자 및 다단 조판은 모두 굳이 미디어 쿼리를 필요로 하지 않고도 가변적이며 심지어 반응형 구성 요소를 만들 수 있는 방법을 제공합니다. 미디어 쿼리를 추가하지 않고도 이러한 조판 메서드를 사용해 원하는 것을 달성할 수 있는지 고려할 가치가 있습니다. 예를 들어, 여러분은 적어도 200 픽셀 너비의 카드 집합을 원할 수 있으며, 최대 200 픽셀이라면 주요 문서 부분에 맞아떨어질 수 있습니다. 이는 미디어 쿼리를 전혀 사용하지 않고 격자 조판만으로 얻을 수 있습니다.</p> + +<p>이것은 아래 용법으로 달성될 수 있습니다.</p> + +<pre class="brush: html"><code><ul class="grid"> + <li> + <h2>카드 1</h2> + <p>...</p> + </li> + <li> + <h2>카드 2</h2> + <p>...</p> + </li> + <li> + <h2>카드 3</h2> + <p>...</p> + </li> + <li> + <h2>카드 4</h2> + <p>...</p> + </li> + <li> + <h2>카드 5</h2> + <p>...</p> + </li> +</ul></code></pre> + +<pre class="brush: css"><code>.grid { + list-style: none; + margin: 0; + padding: 0; + display: grid; + gap: 20px; + grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); +} + +.grid li { + border: 1px solid #666; + padding: 10px; +}</code></pre> + +<p><a href="https://mdn.github.io/css-examples/learn/media-queries/grid.html">이 격자 예제를</a> 브라우저에서 열거나 <a href="https://github.com/mdn/css-examples/blob/master/learn/media-queries/grid.html">소스를 보세요</a>.</p> + +<p>상기 예제를 브라우저에서 열면 화면을 넓히거나 좁히거나 하여 열 트랙 수가 변경되는 것을 확인할 수 있습니다. 이 방법의 좋은 점은 격자가 뷰포트 너비를 보는 게 아니라 해당 구성 요소에 맞춰 이용할 수 있는 너비를 살핀다는 것입니다. 당신에게 미디어 쿼리가 전혀 필요하지 않을수도! 있다는 제안으로 이번 절을 마감하는 것은 이상하게 보일 수도 있습니다. 그러나 실제로 미디어 쿼리로 강화된 현대적 조판 메서드를 잘 사용하면 최상의 결과를 얻을 수 있습니다.</p> + +<h2 id="요약정리">요약정리</h2> + +<p>여러분은 이 단원에서 미디어 쿼리에 대해 배웠으며 모바일 우선 반응형 디자인을 실제로 생성하는 방법도 알아 보았습니다.</p> + +<p>우리가 만든 것을 시작점로 더 많은 미디어 쿼리 조건을 테스트할 수 있습니다. 예를 들어, 방문자가 <code>pointer</code> 미디어 기능을 사용하여 거친 포인터를 가지고 있는 것을 감지하면 탐색 메뉴의 크기를 변경할 수 있습니다.</p> + +<p>또한 서로 다른 구성 요소를 추가하고 미디어 쿼리를 추가한다든지 또는 가변상자나 격자와 같은 조판 방법을 사용하는 것이 구성 요소를 반응형으로 만드는 가장 적절한 방법인지 여부를 실험할 수 있습니다. 바른 방식 혹은 그른 방식 따윈 없습니다. 말하자면 어떤 것이 디자인과 콘텐츠에 가장 적합한지 실험하고 관찰해야 합니다.</p> + + + +<p>{{PreviousMenuNext("Learn/CSS/CSS_layout/Responsive_Design", "Learn/CSS/CSS_layout/Legacy_Layout_Methods", "Learn/CSS/CSS_layout")}}</p> + +<h2 id="이번_단위에는">이번 단위에는</h2> + +<ul> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Introduction">씨에스에스 조판 소개</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/일반_흐름">일반 대열</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Flexbox">가변상자</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Grids">격자</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Floats">부동체</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/위치잡기">위치잡기</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Multiple-column_Layout">다단 조판</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/반응형_디자인">반응형 디자인</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/미디어_쿼리_초보자_안내서">미디어 쿼리 초보자 안내서</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/레거시_조판_메서드">레거시 조판 메서드</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/%EC%9D%B4%EC%A0%84_%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80_%EC%A7%80%EC%9B%90">이전 브라우저 지원</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Fundamental_Layout_Comprehension">조판 이해도 필수 평가</a></li> +</ul> diff --git a/files/ko/learn/css/css_layout/반응형_디자인/index.html b/files/ko/learn/css/css_layout/반응형_디자인/index.html new file mode 100644 index 0000000000..b1311448c7 --- /dev/null +++ b/files/ko/learn/css/css_layout/반응형_디자인/index.html @@ -0,0 +1,333 @@ +--- +title: 반응형 디자인 +slug: Learn/CSS/CSS_layout/반응형_디자인 +tags: + - 가변상장 + - 격자 + - 다단 + - 미디어 쿼리 + - 반응형 웹 디자인 + - 유동 격자 + - 이미지 + - 타이포크래피 +translation_of: Learn/CSS/CSS_layout/Responsive_Design +--- +<div>{{learnsidebar}}{{PreviousMenuNext("Learn/CSS/CSS_layout/Multiple-column_Layout", "Learn/CSS/CSS_layout/Media_queries", "Learn/CSS/CSS_layout")}}</div> + +<p>웹디자인 초창기에는 페이지를 구축할 때 매우 구체적인 화면 크기를 공략 대상으로 삼았습니다. 사용자가 웹디자이너가 예상한 것보다 크거나 작은 화면의 기기를 가지고 있다면 원하지 않는 스크롤 막대에서부터 지나치게 긴 길이의 라인, 사용 공간이 부족하게 되는 결과를 낳습니다. 다양한 화면 크기가 등장함에 따라 <em>responsive web design</em> 개념이 등장했습니다. 말하자면 서로 다른 화면 너비와 해상도 등에 맞게 웹 페이지가 조판과 모양을 변경할 수 있는 일련의 실례를 집대성한 것입니다. 이 아이디어가 우리가 멀티 디바이스 웹에 대한 설계 방식을 바꾸게 만든 장본인입니다. 이 문서에서 우리는 그 내용을 숙달하기 위해 당신이 알아야하는 주요 기술을 이해하도록 도울 것입니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">선결 사항:</th> + <td>에이치티엠엘의 기초인 (<a href="/ko/docs/Learn/HTML/Introduction_to_HTML">에이치티엠엘 입문서</a>를 공부하세요), 그리고 씨에스에스의 작동 방식을 파악하기 위해 (<a href="/en-US/docs/Learn/CSS/First_steps">씨에스에스 첫걸음</a>과 <a href="/ko/docs/Learn/CSS/Building_blocks">씨에스에스 구성 블록</a>를 공부하세요.)</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>반응형 디자인의 역사와 핵심적인 계념 파악하기</td> + </tr> + </tbody> +</table> + +<h2 id="웹사이트_조판_역사">웹사이트 조판 역사</h2> + +<p>역사의 어느 시점 여러분이 웹 사이트를 디자인할 때 두 가지 옵션이 있었습니다.</p> + +<ul> + <li>여러분은 웹브라우저 창에 요소를 연장하도록 하는 <em>liquid</em>(유동) 사이트를 만들 수 있습니다.</li> + <li>픽셀 크기가 고정되어 있는 <em>fixed width</em> 사이트를 만들 수 있었습니다.</li> +</ul> + +<p>이러한 두 가지 접근법은 사이트를 디자인하는 사람의 화면에서 가장 보기 좋은 웹 사이트로 귀결되는 경향이 있었습니다! 유동 사이트는 (아래에서 볼 수 있듯이) 디자이너의 화면보다 더 작은 화면에는 찌부러진 디자인이 나오고, 더 큰 화면에는 읽을 수 없을 정도로 길이가 긴 라인을 만들어냅니다.</p> + +<figure><img alt="두 개의 열이 있는 조판이 모바일 크기 뷰포트에서 찌부러집니다." src="https://mdn.mozillademos.org/files/16834/mdn-rwd-liquid.png" style="display: block; height: 406px; width: 300px;"> +<figcaption></figcaption> +</figure> + +<div class="blockIndicator note"> +<p><strong>주석</strong>: 여기 간단한 유동 조판을 보세요: <a href="https://mdn.github.io/css-examples/learn/rwd/liquid-width.html">예제</a>, <a href="https://github.com/mdn/css-examples/blob/master/learn/rwd/liquid-width.html">소스 코드</a>. 예제를 보면 브라우저 창을 안팎으로 드래그하여 서로 다른 크기에 반응해 어떻게 보이는지 확인합니다.</p> +</div> + +<p>고정 폭 사이트는 (아래에서 보듯) 사이트 너비보다 작은 화면상에 수평 스크롤 막대가 생기는 위험이 있고 더 큰 화면상에서는 웹디자인 가장자리에 많은 흰색 공간이 생길 위험이 있습니다.</p> + +<figure><img alt="이동 뷰포트에 수평 스크롤 막대가 있는 조판입니다." src="https://mdn.mozillademos.org/files/16835/mdn-rwd-fixed.png" style="display: block; height: 411px; width: 300px;"> +<figcaption></figcaption> +</figure> + +<div class="blockIndicator note"> +<p><strong>주석</strong>: 여기 간단한 고정 너비 조판을 보세요: <a href="https://mdn.github.io/css-examples/learn/rwd/fixed-width.html">예제</a>, <a href="https://github.com/mdn/css-examples/blob/master/learn/rwd/fixed-width.html">소스 코드</a>. 역시 브라우저 창 크기를 변경할 때 결과를 관찰하세요.</p> +</div> + +<div class="blockIndicator note"> +<p><strong>주석</strong>: 상단 화면는 파이어폭스 개발툴 안에서 <a href="/en-US/docs/Tools/Responsive_Design_Mode">반응형 디자인 모드</a>을 사용해 갈무리 한 것입니다.</p> +</div> + +<p>모바일 웹이 첫 번째 피처폰의 등장으로 현실화되기 시작하면서 모바일을 수용하고자 하는 회사들은 일반적으로 (종종 <em>m.example.com</em> 또는 <em>example.mobi</em> 이런 식의) 서로 다른 URL를 사용하여 그들의 사이트의 특별한 모바일 버전을 만들게 됩니다. 이는 해당 사이트의 두 가지 별도 버전을 개발하고 최신 상태로 유지해야 한다는 것을 의미했습니다.</p> + +<p>게다가, 이러한 모바일 사이트들을 경험해보면 종종 매우 축소된 기능을 제공합니다. 모바일 장치가 더욱 강력해지고 전체 웹 사이트를 표시할 수 있게 되면서, 그러한 기능 축소 모바일 버전 사이트에 갖힌 자신을 발견한 모바일 사용자들은 그들이 알고 있는 해당 사이트의 전체 기능이 있는 데스크탑 버전의 정보에 접근할 수 없었기에 좌절감을 안겨주었습니다.</p> + +<h2 id="반응형_디자인의_전신_가변_조판">반응형 디자인의 전신 가변 조판</h2> + +<p>유동 및 고정 너비의 웹사이트 구축 방법의 단점을 해결하기 위해 여러 가지 접근법이 개발되었습니다. 2004년 카메론 아담스는 다양한 화면 해상도에 적응할 수 있는 디자인을 만드는 방법을 설명하는 <a href="http://www.themaninblue.com/writing/perspective/2004/09/21/">해상도 의존 조판</a>이라는 제목의 게시물을 작성했습니다. 이 접근방식은 화면 해상도를 감지하고 정확한 씨에스에스를 로드하려면 자바스크립트가 필요했습니다.</p> + +<p>조이 미클리 길렌워터는 그녀의 <a href="http://zomigi.com/blog/voices-that-matter-slides-available/">작업</a>을 통해 화면을 채우는 것과 완전히 고정된 화면 크기 사이를 만족시키는 평균값을 찾으려고 시도하는 등 가변적인 사이트를 만들 수 있는 다양한 방법을 기술하고 공식화하는 데 산파 역할을 했습니다.</p> + +<h2 id="반응형_디자인">반응형 디자인</h2> + +<p>반응형 디자인이라는 용어는 <a href="https://alistapart.com/article/responsive-web-design/">2010년 이단 마르코트가 만든 신조어로</a> 세 가지 기술을 조합한 용법을 설명하고 있습니다.</p> + +<ol> + <li>첫 번째는 이미 길렌워터에 의해 탐구되고 있던 유동 격자라는 아이디어였으며, 마르코트의 <a href="https://alistapart.com/article/fluidgrids/">유동 격자</a>란(2009년 <code>A List Apart</code>에 발표) 문서에서 읽을 수 있다.</li> + <li>두 번째 기술은 <a href="http://unstoppablerobotninja.com/entry/fluid-images">유동 이미지</a>라는 개념이다. <code>max-width</code> 속성을 <code>100%</code>로 설정하는 매우 간단한 기술을 사용하면 이미지의 포함된 열이 이미지의 고유 크기보다 좁아지면 이미지가 더 작아지지만 더 커지지는 않습니다. 이것은 이미지가 대열이탈이 아니라 가변적인 크기의 열에 맞게 축소될 수 있지만 열이 이미지보다 넓어지면 확대되지 않고 픽셀화될 수 있습니다.</li> + <li>세 번째 핵심 구성요소는 <a href="/ko/docs/Web/CSS/Media_Queries">미디어 쿼리</a>였습니다. 미디어 쿼리는카메론 아담스가 앞서 자바스크립의 사용을 탐구했던 조판 전환 유형을 씨에스에스만을 사용하여 실현합니다. 모든 화면 크기마다 하나씩 조판을 부여하기 보다는 조판을 변경할 수 있었다. 사이드바를 작은 화면에 맞게 재배치하거나 대체 탐색 매뉴를 표시할 수 있습니다.</li> +</ol> + +<p><strong>반응형 웹 디자인은 별도의 기술이 아니다</strong>라는 것을 이해하는 것이 중요합니다. 즉, 웹 디자인에 대한 접근 방식이나 콘텐츠를 보는데 사용되는 장치에 <em>반응</em>할 수 있는 조판 생성에 사용되는 모범 사례 집합을 기술하는 데 사용되는 용어다. 마르코트의 원래 연구에서 이것은 (부동체를 사용하는) 가변 격자와 미디어 쿼리를 의미했지만, 그의 문서가 쓰여진지 거의 10년 만에 반응형으로 동작하는 것이 기본값이 되었다. 현대의 씨에스에스 조판 메서드는 본질적으로 반응형이며 반응형 사이트 설계를 쉽게하기 위해 웹 플랫폼에 새로운 요소들이 내장되어 있습니다.</p> + +<p>이 문서의 나머지 절에서는 반응형 사이트를 만들 때 사용할 수 있는 다양한 웹 플랫폼 기능에 대해 안내할 것입니다.</p> + +<h2 id="미디어_쿼리">미디어 쿼리</h2> + +<p>반응형 디자인은 오롯이 미디어 쿼리 때문에 등장할 수 있었습니다. 미디어 쿼리 수준 3 규격은 2009년 권장사항 후보가 되었으며, 이는 브라우저에서 구현할 준비가 되어 있음을 의미합니다. 미디어 쿼리에서는 일련의 테스트를 실행할 수 있습니다(예로 사용자의 화면이 특정 너비나 특정 해성도보다 큰지 여하에 따라). 씨에스에스를 선택적으로 적용하여 사용자의 필요에 따라 페이지를 적절하게 스타일링합니다.</p> + +<p>예를 들어, 아래 미디어 쿼리는 현재 웹 페이지가 화면 미디어로 표시되고 있는지(따라서 인쇄된 문서가 아님) 확인하며 뷰포트는 적어도 800픽셀 너비인지 테스트합니다. <code>.container</code> 선택기는 씨에스에스는 이 두 가지가 사실인 경우에만 적용됩니다.</p> + +<pre class="brush: css"><code>@media screen and (min-width: 800px) { + .container { + margin: 1em 2em; + } +} </code> +</pre> + +<p>스타일시트에 여러 미디어 쿼리를 추가하여 다양한 화면 크기에 맞는 최적의 전체 조판 또는 조판의 일부를 조정할 수 있습니다. 미디어 쿼리가 도입되고 조판이 변경된 지점을 <em>breakpoints</em>(분기점)라고 합니다.</p> + +<p>미디어 쿼리를 사용할 때 일반적인 접근법은 좁은 화면 장치(예: 휴대폰)에 대한 간단한 단일 열 조판을 만든 다음, 큰 화면인지 점검하고, 화면 폭이 충분하다는 것을 알게 될 때 다단 조판을 구현하는 것이다. 이를 <strong>모바일 우선</strong> 디자인이라고 표현하는 경우가 많다.</p> + +<p><a href="/ko/docs/Web/CSS/Media_Queries">미디어 쿼리</a>에 대한 MDN 문서를 더 찾아보십시요.</p> + +<h2 id="가변_격자">가변 격자</h2> + +<p>반응형 사이트는 분기점 전후로 자체 조판을 변경할 뿐만 아니라 가변 격자상에도 동일하게 구축됩니다. 가변 격자는 현존하는 모든 장치 크기를 공략 대상으로 삼을 필요가 없으며, 그 대상에 대한 완벽한 픽셀 조판을 구축할 필요가 없다는 것을 의미합니다. 완벽한 픽셀 접근 방식은 존재하는 다양한 크기의 장치들이 엄청나게 많고, 적어도 데스크톱에서는 사람들이 항상 브라우저 창을 최대화하지는 않는다는 사실을 감안할 때 불가능할 것입니다.</p> + +<p>가변 격자를 사용하면 요소를 분기점에 추가하고, 콘텐츠가 불량으로 보이기 시작하는 지점에서 디자인을 변경할 수 있습니다. 예를 들어, 화면 크기가 커지면 라인 길이가 읽을 수 없게 길어지거나 상자가 좁아질 때 각 라인에 두 단어로 찌브러집니다.</p> + +<p>반응형 디자인 초창기에는 조판 기능을 수행하는 유일한 옵션은 <a href="/en-US/docs/Learn/CSS/CSS_layout/Floats">부동체</a>를 사용하는 것이 었습니다. 가변 부동 조판은 각 요소에 백분율 너비를 부여하고 조판 전체의 너비가 100%를 넘지 않도록 보장함으로써 달성되었습니다. 마르코트는 유동 격자와 관련 그의 원래 작품에서 픽셀을 사용하여 설계된 조판을 채택하여 백분율로 변환하는 공식을 상세히 설명했습니다.</p> + +<pre><code>target / context = result </code> +</pre> + +<p>예를 들어, 목표 열 크기가 60픽셀이고, 거기에 들어갈 상황(혹은 컨테이너)가 이 960픽셀이면, 씨에스에스에서 사용할 수 있는 값을 얻기 위해 우선 60픽셀을 960픽셀로 나누고 거기에 소수점을 오른쪽으로 두칸 이동합니다.</p> + +<pre class="brush: css"><code>.col { + width: 6.25%; /* 60 / 960 = 0.0625 */ +} </code> +</pre> + +<p>이 접근 방식은 오늘날 웹상에 여러 곳에서 발견될 것이며, 여기 우리의 <a href="/en-US/docs/Learn/CSS/CSS_layout/Legacy_Layout_Methods">레거시 조판 메서드</a> 문서의 조판 절에 문서화되어 있습니다. 여러분이 업무 중에 이 접근법을 사용하는 웹 사이트를 발견할 가능성이 높기 때문에 부동 기반의 가변 조판을 사용하여 현대적인 사이트를 구축하지는 않겠지만, 그 내용을 이해할 가치는 있습니다.</p> + +<p>다음 예제에서는 미디어 쿼리와 가변 격자를 사용하여 간단한 반응형 디자인를 보여줍니다. 좁은 화면상에서는 상자가 상대 요소 위해 겹겹이 쌓여지는 조판 형태로 표시됩니다.</p> + +<figure><img alt="상자 무리가 상대 요소의 상단에 수직으로 겹겹이 쌓이는 모바일뷰 조판입니다." src="https://mdn.mozillademos.org/files/16836/mdn-rwd-mobile.png" style="display: block; height: 407px; width: 300px;"> +<p>On wider screens they move to two columns:</p> + +<figcaption></figcaption> +</figure> + +<figure><img alt="2단 조판이 적용된 데스크탑 뷰입니다." src="https://mdn.mozillademos.org/files/16837/mdn-rwd-desktop.png" style="display: block; height: 217px; width: 600px;"> +<figcaption></figcaption> +</figure> + +<div class="blockIndicator note"> +<p><strong>주석</strong>: 여러분은 여기서 <a href="https://mdn.github.io/css-examples/learn/rwd/float-based-rwd.html">실례</a>를 찾아볼 수 있으며, 이 예제에 대한 <a href="https://github.com/mdn/css-examples/blob/master/learn/rwd/float-based-rwd.html">소스 코드</a>를 깃허브에서 찾을 수 있습니다.</p> +</div> + +<h2 id="현대_조판_기술">현대 조판 기술</h2> + +<p><a href="/en-US/docs/Learn/CSS/CSS_layout/Multiple-column_Layout">다단 조판</a>과 <a href="/en-US/docs/Learn/CSS/CSS_layout/Flexbox">가변상자</a>와 <a href="/en-US/docs/Learn/CSS/CSS_layout/Grids">격자</a>와 같은 현대 조판 메서드는 기본값으로 응답형입니다. 그것들은 모두 여러분이 가변 격자를 만들려 한다고 가정하고 그렇게 동작하도록 편리한 방법을 제공합니다.</p> + +<h3 id="다단">다단</h3> + +<p>이러한 조판 메서드 중 가장 오래된 것은 다단입니다. 여러분이 <code>column-count</code>를 지정하면, 이는 여러분이 콘텐츠를 나누고자 하는 단의 숫자를 나타냅니다. 그런 다음 브라우저는 다단의 크기를 화면 크기에 따라 변경되는 크기로 계산합니다.</p> + +<pre class="brush: css"><code>.container { + column-count: 3; +} </code> +</pre> + +<p><code>column-width</code>을 지정하는 대신 <em>minimum</em> 너비를 지정하는 것입니다. 브라우저는 컨테이너에 안착할 수 있는 만큼으로 지정한 해당 너비를 가진 열을 최대한 많이 생성하고 난 뒤에 다음 모든 열 사이에서 나머지 공간을 공유합니다. 따라서 열의 수는 공간이 얼마나 되는지에 따라 달라집니다.</p> + +<pre class="brush: css"><code>.container { + column-width: 10em; +} </code> +</pre> + +<h3 id="가변상자">가변상자</h3> + +<p>가변상자에서 가변 항목은 초깃값 동작으로 컨테이너의 공간에 따라 항목 사이의 공간을 축소하고 분배합니다. <code>flex-grow</code> 및 <code>flex-shrink</code> 값을 변경하면 해당 항목에 주어진 주변 공간이 남거나 모질라게 될 경우 원하는 동작 방식을 표기할 수 있습니다.</p> + +<p>아래 예제에서 가변 항목은 가변 컨테이너 안에서 각각 동일한 양의 공간을 차지하며, <a href="/ko/docs/Learn/CSS/CSS_layout/Flexbox#가변_항목의_가변_크기_조정">가변상자: 가변 항목의 가변 크기 조정</a>에서 설명했듯이 <code>flex: 1</code>식의 약칭을 사용할 수 있습니다.</p> + +<pre class="brush: css"><code>.container { + display: flex; +} + +.item { + flex: 1; +} </code> +</pre> + +<div class="blockIndicator note"> +<p><strong>참고</strong>: 예제로써 상기된 간단한 반응형 조판을 재구축했는데 이번에는 가변상자를 사용했습니다. 여러분은 더 이상 낮설은 백분율 값을 사용하여 열의 크기를 계산할 필요가 없는 방법을 보게 됩니다: <a href="https://mdn.github.io/css-examples/learn/rwd/flex-based-rwd.html">예제</a>, <a href="https://github.com/mdn/css-examples/blob/master/learn/rwd/flex-based-rwd.html">소스 코드</a>.</p> +</div> + +<h3 id="씨에스에스_격자">씨에스에스 격자</h3> + +<p>씨에스에스 격자 조판에서 <code>fr</code> 단위는 격자 트랙 전역에 걸쳐 이용할 수 있는 공간을 분배할 수 있습니다. 다음 예에서는 <code>1fr</code> 크기의 트랙 3개가 있는 격자 컨테이너를 만듭니다. 이렇게 하면 3개의 열 트랙이 생성되며, 각 트랙은 컨테이너에 있는 사용 가능한 공간\의 한 부분을 차지합니다. 여러분은 <a href="ko/docs/Learn/CSS/CSS_layout/Grids#fr_단위를_포함하는_가변_격자">fr 단위를 포함한 가변 격자</a>라는 격자 조판 학습 주제에서 격자를 생성하는 이같은 접근 방식에 대해 자세히 알 수 있습니다.</p> + +<pre class="brush: css"><code>.container { + display: grid; + grid-template-columns: 1fr 1fr 1fr; +} </code> +</pre> + +<div class="blockIndicator note"> +<p><strong>참고</strong>: 격자 조판 버전은 .wrapper <a href="https://mdn.github.io/css-examples/learn/rwd/grid-based-rwd.html">예제</a>상에 열을 정의할 수 있으므로 더 간단합니다: <a href="https://github.com/mdn/css-examples/blob/master/learn/rwd/grid-based-rwd.html">소스 코드</a>.</p> +</div> + +<h2 id="반응형_이미지">반응형 이미지</h2> + +<p>반응 이미지에 대한 가장 간단한 접근법은 반응형 디자인에 관한 마르코트의 초창기 문서에서 설명한 바와 같습니다. 기본적으로 필요한 최대 크기의 이미지를 촬영하여 그것을 축소할 수 있습니다. 이것은 오늘날에도 사용되는 접근법이며 대부분의 스타일 시트에서 다음과 같은 씨에스에스를 어디선가는 발견할 수 있습니다.</p> + +<pre class="brush: css"><code>img { + max-width: 100%: +} </code> +</pre> + +<p>이 접근법에는 명백한 단점이 있습니다. 해당 이미지는 고유 크기보다 훨씬 작게 표시될 수 있어 대역폭 낭비입니다. 다시말해 모바일 사용자는 브라우저 창에서 실제로 보는 것의 몇 배 크기의 이미지를 다운로드하게 되니 낭비입니다. 또한, 데스크톱과 같은 이미지 가로 세로 비율을 모바일에서 원하지 않을 수도 있습니다. 예를 들어, 모바일의 경우 정사각형 이미지가 좋을 수 있지만 데스크톱상에는 같은 이미지를 가로 보기처럼 장면을 보여줍니다. 또는 모바일 상의 이미지의 크기가 작다는 것을 이해하면서도 서로 다른 이미지를 모두 보여주고 싶을 경우가 있습니다. 말하자면 작은 화면 크기에서 더 쉽게 해석될 수 있는 이미지를 말합니다. 이런 것들은 단순히 이미지를 축소해서는 달성할 수 없습니다.</p> + +<p>반응형 이미지는 <code><a href="/en-US/docs/Web/HTML/Element/picture"><picture></a></code> 요소와 <code><a href="/en-US/docs/Web/HTML/Element/img"><img></a></code>, <code>srcset</code>과 <code>sizes</code> 속성은 이러한 문제를 모두 해결합니다. 여러분은 "힌트"(이미지에 가장 적합한 화면 크기와 해상도를 설명하는 메타 데이터)와 함께 여러 크기를 제공할 수 있으며, 브라우저는 각 장치에 가장 적합한 이미지를 선택하며, 사용자가 사용하고 있는 장치에 적합한 이미지 크기를 다운로드할 수 있도록 담보합니다.</p> + +<p>또한 다른 화면 크기에서 사용되는 이미지를 <em>art direct</em>할 수 있으므로 서로 다른 화면 크기에 대해 서로 다른 자르기 또는 완전히 다른 이미지를 제공할 수 있습니다.</p> + +<p>이곳 MDN 사이트의 에이치티엠엘 학습 섹션에서 <a href="/ko/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images">반응형 이미지</a>에 대한 자세한 안내서를 찾을 수 있습니다.</p> + +<h2 id="반응형_타이포그래피">반응형 타이포그래피</h2> + +<p>반응형 타이포그래피 개념은 이전 작업에서 다루지 않은 반응형 디자인의 요소입니다. 본질적으로, 이것은 화면 부동산의 크기가 더 작아지거나 더 커지거나하는 것을 반영하기 위해 미디어 쿼리 구문 안에서 폰트 크기를 변경하는 것을 말합니다.</p> + +<p>이 예제에서 우리는 수준 1 머리글을 <code>4rem</code>로 설정하려고 합니다. 즉, 기본 글꼴 크기의 4배입니다. 정말 큰 제목이네요! 우리는 더 큰 화면 크기상에서만 이 코끼리만한 머리글을 원하기 때문에, 우리는 먼저 더 작은 머리글을 만들고, 미디어 쿼리를 사용해 조건에 맞으면 그것을 더 큰 크기로 덮어쓰기 하면됩니다. 여기서 조건은 사용자가 적어도 1200px의 화면 크기의 기기를 가진 경우가 해당됩니다.</p> + +<pre class="brush: css"><code>html { + font-size: 1em; +} + +h1 { + font-size: 2rem; +} + +@media (min-width: 1200px) { + h1 { + font-size: 4rem; + } +} </code> +</pre> + +<p>상기한 반응형 격자 예제를 편집했고, 거기에 더해 이미 제시된 메서드를 사용하는 응답형 유형을 포함시켰습니다. 조판이 2개의 열 버전으로 이동함에 따라 머리글 크기가 어떻게 전환하는지 볼 수 있습니다.</p> + +<p>모바일에서는 머리글이 더 작다:</p> + +<figure><img alt="머리글 크기가 작은 스택 모양의 조판입니다." src="https://mdn.mozillademos.org/files/16838/mdn-rwd-font-mobile.png" style="display: block; height: 407px; width: 300px;"> +<p>On desktop however we see the larger heading size:</p> + +<figcaption></figcaption> +</figure> + +<figure><img alt="큰 머리글이 딸린 두개의 열 조판입니다." src="https://mdn.mozillademos.org/files/16839/mdn-rwd-font-desktop.png" style="display: block; height: 169px; width: 600px;"> +<figcaption></figcaption> +</figure> + +<div class="blockIndicator note"> +<p><strong>참고</strong>: 이 예제의 실제 구현 장면: <a href="https://mdn.github.io/css-examples/learn/rwd/type-rwd.html">예제</a>, <a href="https://github.com/mdn/css-examples/blob/master/learn/rwd/type-rwd.html">소스 코드</a>.</p> +</div> + +<p>타이포그래피에 대한 이러한 접근 방식이 보여주듯이, 미디어 쿼리를 제한하여 페이지 조판만 변경할 필요는 없습니다. 그들 접근법을 사용하여 어떤 요소라도 조정해서 대체 화면 크기에 맞는 더 유용하고 매력적인 요소를 만들 수 있다.</p> + +<h3 id="반응형_타이포그래피에_대한_뷰포트_단위_사용하기">반응형 타이포그래피에 대한 뷰포트 단위 사용하기</h3> + +<p>흥미로운 접근 방식은 반응형 타이포그래피를 사용하기 위해 뷰포트 단위 <code>vw</code>를 사용할 수 있다는 점이다. <code>1vw</code>는 뷰포트 너비의 1%와 동일하며, <code>vw</code>를 사용하여 글꼴 크기를 설정하면 항상 뷰포트 크기와 관련이 있다는 것을 의미한다.</p> + +<pre class="brush: css">h1 { + font-size: 6vw; +}</pre> + +<p>위의 작업 수행에서의 문제는 사용자가 vw 단위를 사용하여 텍스트 집합을 확대/축소하는 기능을 상실하는 데 있다. <strong>따라서 여러분은 뷰포트 단위만으로 텍스트를 설정해서는 안 된다</strong>.</p> + +<p>해결책이 하나 있다. <code><a href="/en-US/docs/Web/CSS/calc">calc()</a></code>를 사용하는 것이다. 즉, <code>em</code>와 같은 고정된 크기를 사용하여 속성값 집합에 <code>vw</code> 단위를 추가하면 텍스트는 여전히 확대/축소할 수 있다. 본질적으로 <code>vw</code> 단위는 확대/축소 값에 더해 추가된다.</p> + +<pre class="brush: css">h1 { + font-size: calc(1.5rem + 3vw); +}</pre> + +<p>즉, 머리글에 대한 폰트 크기를 한 번만 지정하면 된다. 크기를 모바일용으로 따로 설정할 게 아니라 미디어 쿼리 내에서 크기를 재정의한다는 말이다. 그러면 뷰포트의 크기가 커질수록 글꼴은 점차 커진다.</p> + +<div class="blockIndicator note"> +<p>이에 대한 예제의 실현: <a href="https://mdn.github.io/css-examples/learn/rwd/type-vw.html">예제</a>, <a href="https://github.com/mdn/css-examples/blob/master/learn/rwd/type-vw.html">소스 코드</a>.</p> +</div> + +<h2 id="뷰포트_메타_테그">뷰포트 메타 테그</h2> + +<p>응답형 페이지의 에이치티엠엘 소스를 보면 일반적으로 문서의 <code><head></code>에서 다음과 같은 {{htmlelement("meta")}} 태그를 볼 수 있다.</p> + +<pre class="brush: html"><code><meta name="viewport" content="width=device-width,initial-scale=1"></code> +</pre> + +<p>이 메타 태그는 뷰포트의 너비를 장치의 너비로 설정하여 문서를 의도한 크기의 100%로 확장해야 한다고 모바일 브라우저에게 알려줍니다. 이로써 여러분이 의도한 대로 모바일에 최적화된 크기로 문서를 표시합니다.</p> + +<p>왜 이런 것이 필요할까요? 모바일 브라우저는 뷰포트 너비에 대해 거짓말을 하는 경향이 있기 때문이다.</p> + +<p>이 메타 태그는 원래 iPhone이 출시되고 사람들이 작은 전화 화면에서 웹 사이트를 보기 시작했을 때 대부분의 사이트가 모바일 최적화되지 않았기 때문에 존재합니다. 따라서 모바일 브라우저는 뷰포트 너비를 960픽셀로 설정하게 됩니다. 해당 너비로 페이지를 렌더링하고, 그 결과를 데스크톱 조판의 확대 버전으로 표시합니다. 다른 모바일 브라우저(예를 들어 구글 안드로이드)도 똑같은 일을 합니다. 사용자들은 웹사이트를 확대하고 이리저리 끌어 옮기며(panning) 그들이 관심을 갖는 부분을 볼 수 있었지만, 모양이 형편 없었습니다. 만약 여러분이 반응형 디자인이 아닌 사이트를 우연히 발견하게 된다면, 여러분은 오늘날에도 이런 걸 보게 될 것입니다.</p> + +<p>문제는 분기점과 미디어 쿼리를 포함하는 응답형 디자인이 모바일 브라우저에서 의도한 대로 작동하지 않는다는 점에 있습니다. 여러분이 480px 뷰포트 너비나 그 이하에서 시작하는 좁은 화면 조판을 갖고 있고 뷰포트가 960px로 설정되어 있다면 좁은 화면 조판을 모바일에서 절대 볼 수 없게 된다. <code>width=device-width</code>를 설정하면 애플의 기본값인 <code>width=960px</code>를 장치의 실재 너비로 재지정하므로 당신의 미디어 쿼리가 의도한 대로 작동합니다.</p> + +<p>따라서 에이치티엠엘 문서의 헤더 부분에 상기 에이치티엠엘 라인을 <em>항상</em> 포함해야 합니다.</p> + +<p>뷰포트 메타 태그와 함께 사용할 수 있는 다른 설정이 있지만 일반적으로 상기 에이치티엠엘 라인이면 여러분이 사용하고자 하는 내용에 해당합니다.</p> + +<ul> + <li><code>initial-scale</code>: 페이지의 초기 확대/축소 지정은 1로 설정된다.</li> + <li><code>height</code>: 뷰포트 높이를 특정값으로 지정합니다.</li> + <li><code>minimum-scale</code>: 최소 확대/축소 수준을 설정합니다.</li> + <li><code>maximum-scale</code>: 최대 확대/축소 수준을 설정합니다.</li> + <li><code>user-scalable</code>: <code>no</code>값을 지정하게 되면 확대/축소를 방지합니다.</li> +</ul> + +<p>여러분은 <code>minimum-scale</code>와 <code>maximum-scale</code> 사용을 피해야하며, 특히 <code>user-scalable</code>를 <code>no</code>로 설정하는 것도 피해야 합니다. 사용자는 필요한 만큼 확대하거나 축소할 수 있어야 합니다.이를 방지하면 접근성 문제가 발생합니다.</p> + +<div class="blockIndicator note"> +<p><strong>참고</strong>: 뷰포트 메타 태그를 대체하기 위해 고안된 씨에스에스 @ 규칙이 있습니다. <a href="/ko/docs/Web/CSS/@viewport">@viewport</a> 그러나 브라우저 지원이 매우 형편없습니다. 그것은 인터넷 익스플로러와 에지에서 구현되었지만, 일단 크롬 기반 에지가 출시되면 더 이상 에지 브라우저의 일부가 되지 않게 됩니다.</p> +</div> + +<h2 id="요약정리">요약정리</h2> + +<p>반응형 디자인은 디자인이 보여지는 당해 환경에서 반응하는 사이트 및 애플리케이션 디자인을 말합니다. 그것은 많은 씨에스에스와 에이치티엠엘 기능과 기술을 망라하며 이제 기본값으로 우리가 웹사이트를 구축할 때 필수적인 방법입니다. 여러분이 휴대폰으로 방문하는 사이트를 생각해보세요. 데스크톱 버전이 축소된 사이트, 또는 사물을 찾기 위해 옆으로 스크롤해야 하는 사이트를 우연히 발견한다는 것은 상당히 이례적인 일일 것입니다. 그렇게 된 것은 웹이 반응형으로 디자인하는 접근방식으로 옮겨갔기 때문입니다.</p> + +<p>또한 이번 단원에서 배운 조판 메서드의 도움으로 반응형 디자인을 달성하기가 훨씬 쉬워졌습니다. 여러분이 당대 웹 개발에 신출내기라면, 반응형 디자인 초창기보다 훨씬 많은 도구가 마련되어 있으니 맘껏 이용하십시요. 따라서 당신이 참조하고 있는 어떤 자료의 연혁을 확인할 가치가 있습니다. 역사적 기록 문서로서 여전히 유용하지만, 사이트 방문자가 이용하는 장치가 무엇이건 관계없이 우아하고 유용한 디자인을 훨씬 쉽게 생성하려면 씨에스에스와 에이치티엠엘의 현대적 용법이 정답입니다.</p> + +<p>{{PreviousMenuNext("Learn/CSS/CSS_layout/Multiple-column_Layout", "Learn/CSS/CSS_layout/Media_queries", "Learn/CSS/CSS_layout")}}</p> + +<h2 id="이번_단위에는">이번 단위에는</h2> + +<ul> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Introduction">씨에스에스 조판 소개</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/일반_흐름">일반 대열</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Flexbox">가변상자</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Grids">격자</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Floats">부동체</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/위치잡기">위치잡기</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Multiple-column_Layout">다단 조판</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/반응형_디자인">반응형 디자인</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/미디어_쿼리_초보자_안내서">미디어 쿼리 초보자 안내서</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/레거시_조판_메서드">레거시 조판 메서드</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/%EC%9D%B4%EC%A0%84_%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80_%EC%A7%80%EC%9B%90">이전 브라우저 지원</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Fundamental_Layout_Comprehension">조판 이해도 필수 평가</a></li> +</ul> diff --git a/files/ko/learn/css/css_layout/위치잡기/index.html b/files/ko/learn/css/css_layout/위치잡기/index.html new file mode 100644 index 0000000000..76a491ae0e --- /dev/null +++ b/files/ko/learn/css/css_layout/위치잡기/index.html @@ -0,0 +1,585 @@ +--- +title: 위치잡기 +slug: Learn/CSS/CSS_layout/위치잡기 +tags: + - 고정 + - 글 + - 상대 + - 씨에스에스 + - 안내서 + - 위치잡기 + - 절대 + - 조판 + - 초보자 + - 코딩스크립팅 +translation_of: Learn/CSS/CSS_layout/Positioning +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/CSS/CSS_layout/Floats", "Learn/CSS/CSS_layout/Multiple-column_Layout", "Learn/CSS/CSS_layout")}}</div> + +<p class="summary">당신이 일반 문서 조판 대열에서 요소를 끄집어 내어, 그것이 다르게 행동하게 만들수 있게 해주는 것이 위치잡기다. 예를 들어 상대 요소 위에 놓거나 브라우저 뷰 포트 내부의 동일한 위치를 항상 유지하게 해준다. 이 문서는 서로 다른 {{cssxref("position")}} 값을 설명하고, 그 걸 사용하는 방법에 대해서도 설명한다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">선결 사항:</th> + <td>에이치티엠엘의 기초 (<a href="/ko/docs/Learn/HTML/Introduction_to_HTML">에이치티엠엘 입문서</a>)와 씨에스에스 작동 방식에 대한 개념(<a href="/en-US/docs/Learn/CSS/Introduction_to_CSS">씨에스에스 입문서</a>를 공부하세요.)</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>씨에스에스 위치잡기가 작동하는 방법 배우기</td> + </tr> + </tbody> +</table> + +<p>가능하면 우리 깃허브 저장소에 있는 <code><a href="http://mdn.github.io/learning-area/css/css-layout/positioning/0_basic-flow.html">0_basic-flow.html</a></code> 파일의 사본을 가지고 당신의 컴퓨터상에서 해당 연습을 함께 따라해보시길 바랍니다. (<a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/positioning/0_basic-flow.html">여기 소스 코드</a>)가 있으니 그걸 착수 파일로 이용하십시요.</p> + +<h2 id="위치잡기_소개">위치잡기 소개</h2> + +<p>크게봐서 위치잡기의 개념은 위에서 설명했듯 기본 문서 대열에 따른 동작을 무시하고 흥미로운 효과를 낼 수 있도록 하는 것입니다. 조판 내부의 일부 상자의 위치를 기본 조판 대열 위치에서 약간 변경한다거나, 약간 기묘하거나, 편치않은 느낌을 주고 싶다면 어떨까? 위치잡기가 바로 당신의 도구입니다. 또는 페이지의 다른 부분의 상위에 부동(浮動)하는 사용자 인터페이스 요소를 만들고 싶다라거나 아울러 페이지가 스크롤된 정도와 상관없이 항상 브라우저 창 내부의 동일한 위치에 놓이게 하고 싶다면? 위치잡기는 그런 조판 작업을 가능하게 합니다.</p> + +<p>에이치티엠엘 요소에 적용될 수 있는 여러 가지 유형의 위치잡기가 존재합니다. 어떤 요소상에 특정 유형의 위치잡기가 활성화되도록 하기 위해 {{cssxref("position")}} 속성을 사용합니다.</p> + +<h3 id="정적_위치잡기">정적 위치잡기</h3> + +<p>정적 위치잡기는 모든 요소에 주어지는 기본값입니다. 즉, "요소를 문서 조판 대열상에 일반 위치에 배치하라는 것으로 여기서 특별한 것은 없습니다."</p> + +<p>이를 입증한다거나, 이어질 섹션에서 다룰 예제를 설정하려면 먼저 에이치티엠엘상에 두 번째 {{htmlelement("p")}} 요소에 <code>positioned</code>라는 클래스를 추가하십시오:</p> + +<pre class="brush: html"><p class="positioned"> ... </p></pre> + +<p>이제 다음과 같은 규칙을 당신의 씨에스에스 하단에 추가하십시요:</p> + +<pre class="brush: css">.positioned { + position: static; + background: yellow; +}</pre> + +<p>이제 저장하고 새로고침하면 두 번째 단락의 배경 색깔이 업데이트된 것을 제외하고 다른 차이가 없다는 것이 확인될 것입니다. 아무 문제없습니다. 앞에서 얘기했듯이 정적 위치잡기는 기본값으로 주어진 동작입니다!</p> + +<div class="note"> +<p><strong>주석</strong>: 이 시점에 예제의 실제 구현 장면을 <code><a href="http://mdn.github.io/learning-area/css/css-layout/positioning/1_static-positioning.html">1_static-positioning.html</a></code>에서 볼 수 있습니다.(<a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/positioning/1_static-positioning.html">소스 코드는 여기서 보세요</a>).</p> +</div> + +<h3 id="상대_위치잡기">상대 위치잡기</h3> + +<p>상대 위치잡기는 우리가 살펴 첫 번째 위치 유형입니다. 이것은 정적 위치 결정과 매우 유사합니다. 단, 일단 정상 조판 대열상에 위치잡기할 요소가 자리를 잡고나면 페이지의 다른 요소와 중첩되는 것을 포함하여 최종 위치를 수정할 수 있습니다. 당신의 코드에 있는 <code>position</code> 선언을 업데이트하십시요.</p> + +<pre class="brush: css">position: relative;</pre> + +<p>현 시점에서 저장하고 새로 고침하면 전혀 변경된 결과가 확인되지 않습니다. 그럼 요소의 위치를 어떻게 수정할까요? 다음 절에서 설명하겠지만, {{cssxref("top")}}, {{cssxref("bottom")}}과 {{cssxref("left")}}, {{cssxref("right")}}을 사용해야 합니다.</p> + +<h3 id="상하_좌우_위치잡기_소개">상하 좌우 위치잡기 소개</h3> + +<p>{{cssxref("top")}}, {{cssxref("bottom")}}와 {{cssxref("left")}}, and {{cssxref("right")}}는 {{cssxref("position")}}과 나란히 사용되어 기준 위치에 비례해 정확한 위치잡기를 지정한다. 이를 시험하려면 다음 선언문을 씨에스에스 <code>.positioned</code> 규칙에 추가하십시오:</p> + +<pre>top: 30px; +left: 30px;</pre> + +<div class="note"> +<p><strong>참고</strong>: 이러한 속성의 값은 당신이 논리적으로 예상할 수 있는 모든 <a href="/ko/docs/Learn/CSS/Introduction_to_CSS/Values_and_units">단위</a>를 취할 수 있습니다. 예로 pixels, mm, rems, % 등이 해당한다.</p> +</div> + +<p>이제 저장하고 새로고침하면 다음과 같은 내용의 결과를 얻을 것입니다:</p> + +<div class="hidden"> +<pre class="brush: html"><h1>상대 위치잡기</h1> + +<p>나는 기본 볼록 수준 요소입니다. 나와 인접한 블록 수준 요소는 내 아래 새 줄에 자리합니다.</p> + +<p class="positioned">기본적으로 우리는 부모 요소의 너비 100%에 걸쳐 있습니다. 우리의 총 너비와 총 높이는 우리의 콘텐츠 + 패딩 + 테두리 너비 및 높이입니다.</p> + +<p>우리는 여백으로 구분됩니다. 여백 축소로 때문에 우리의 여백 중의 하나의 너비로 구분됩니다. 두게의 여백이 아니라.</p> + +<p>인라인 요소 <span>이 것과 같은</span> 그리고 <span>이것이</span> 차례로 같은 라인에, 그리고 같은 라인에 공간이 있을 경우 인접한 텍스트 노드에 자리를 잡게 됩니다. 인라인 요소가 대열이탈할 경우 <span>(이 경우와 같이 텍스트를 포함했을 경우) 가능하면 새 줄로 접혀들어갑니다.)</span>, 그렇지 않으면 새로운 라인으로 계속 진행할 것입니다. 이 이미지가 하는 것처럼: <img src="https://mdn.mozillademos.org/files/13360/long.jpg"></p></pre> + +<pre class="brush: css">body { + width: 500px; + margin: 0 auto; +} + +p { + background: aqua; + border: 3px solid blue; + padding: 10px; + margin: 10px; +} + +span { + background: red; + border: 1px solid black; +} + +.positioned { + position: relative; + background: yellow; + top: 30px; + left: 30px; +}</pre> +</div> + +<p>{{ EmbedLiveSample('상하_좌우_위치잡기_소개', '100%', 500) }}</p> + +<p>근사하죠, 그쵸? 좋습니다. 그러나 이것은 아마도 여러분이 기대했던 것이 아니었을 것입니다. 우리가 좌측 상단을 지정했는데 왜 우측 하단으로 이동했을까요? 처음에는 비논리적으로 들릴지 모르지만, 이것은 상대적 위치잡기가 작용하는 방식일 뿐입니다. 즉, 위치가 지정된 상자의 특정 측면을 밀어서 반대 방향으로 움직이는 보이지 않는 힘이 있다고 생각할 필요가 있습니다. 예를 들어, <code>top: 30px;</code>를 지정하면 힘은 상자 상단을 밀어서 30px 아래로 이동하게 만듭니다.</p> + +<div class="note"> +<p><strong>참고</strong>: 이 시점에 예제의 실제 구현 장면을 <code><a href="http://mdn.github.io/learning-area/css/css-layout/positioning/2_relative-positioning.html">2_relative-positioning.html</a></code>에서 확인할 수 있습니다(<a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/positioning/2_relative-positioning.html">소스 코드 보기</a>).</p> +</div> + +<h3 id="절대_위치잡기">절대 위치잡기</h3> + +<p>절대적인 위치 결정은 매우 다른 결과를 가져옵니다. 당신의 소스 코드에 다음과 같이 위치 선언을 변경해 보겠습니다.</p> + +<pre>position: absolute;</pre> + +<p>지금 저장한 다음에 새로고침하면 다음과 같은 것이 확인되어야 합니다:</p> + +<div class="hidden"> +<pre class="brush: html"><h1>절대 위치잡기</h1> + +<p>나는 기본 볼록 수준 요소입니다. 나와 인접한 블록 수준 요소는 내 아래 새 줄에 자리합니다.</p> + +<p class="positioned">기본적으로 우리는 부모 요소의 너비 100%에 걸쳐 있습니다. 우리의 총 너비와 총 높이는 우리의 콘텐츠 + 패딩 + 테두리 너비 및 높이입니다.</p> + +<p>우리는 여백으로 구분됩니다. 여백 축소로 때문에 우리의 여백 중의 하나의 너비로 구분됩니다. 두게의 여백이 아니라.</p> + +<p>인라인 요소 <span>이 것과 같은</span> 그리고 <span>이것이</span> 차례로 같은 라인에, 그리고 같은 라인에 공간이 있을 경우 인접한 텍스트 노드에 자리를 잡게 됩니다. 인라인 요소가 대열이탈할 경우 <span>(이 경우와 같이 텍스트를 포함했을 경우) 가능하면 새 줄로 접혀들어갑니다.)</span>, 그렇지 않으면 새로운 라인으로 계속 진행할 것입니다. 이 이미지가 하는 것처럼: <img src="https://mdn.mozillademos.org/files/13360/long.jpg"></p></pre> + +<pre class="brush: css">body { + width: 500px; + margin: 0 auto; +} + +p { + background: aqua; + border: 3px solid blue; + padding: 10px; + margin: 10px; +} + +span { + background: red; + border: 1px solid black; +} + +.positioned { + position: absolute; + background: yellow; + top: 30px; + left: 30px; +}</pre> +</div> + +<p>{{ EmbedLiveSample('절대_위치잡기', '100%', 420) }}</p> + +<p>우선, 위치잡기 요소가 원래 있었어야 했던 문서 대열 속 위치에 있던 간격은 더 이상 존재하지 않는다는 점에 유의하십시오. 즉 간격이 더 이상 존재하지 않는 것처럼 첫 번째와 세 번째 요소가 붙어 버렸습니다! 어떤 면에서는, 이것은 사실입니다. 절대적으로 위치한 요소는 더 이상 일반 문서 조판 대열에서 존재하지 않습니다. 대신 다른 모든 것과는 별개로 독자적인 레이어상에 놓여 있습니다. 이것은 매우 유용합니다. 즉, 페이지의 다른 요소의 위치와 간섭하지 않는 격리된 사용자 인터페이스 기능을 만들 수 있습니다. 예를 들어 팝업 정보 상자 및 제어 메뉴, 롤오버 패널, 페이지 어느 곳에서나 끌어서 놓기할 수 있는 유저 인터페이스 페이지 등등…</p> + +<p>둘째, 요소의 위치가 변경되었음을 알아차립시다. 이는 {{cssxref("top")}}, {{cssxref("bottom")}}과 {{cssxref("left")}}, {{cssxref("right")}}가 절대 위치잡기에 해당해 다른 방식으로 작동하기 때문입니다. 요소가 진입해야 하는 방향을 지정하기 보다는 요소가 (부모) 콘테이너 요소의 상하좌우 측면으로부터 떨어지는 간격을 지정되어야 합니다. 따라서 이 경우, 내 말은 절대 위치잡기 요소는 "콘테이너 요소"의 상단에서 30px, 왼쪽에서 30px에 위치에 놓여야 한다는 말입니다.</p> + +<div class="note"> +<p><strong>참고</strong>: 당신이 필요하다면 요소의 크기를 재지정하기 위해 {{cssxref("top")}}, {{cssxref("bottom")}}과 {{cssxref("left")}}, {{cssxref("right")}}를 사용할 수 있습니다. 당신이 위치잡기한 요소에 <code>top: 0; bottom: 0; left: 0; right: 0;</code>과 <code>margin: 0;</code>를 지정한 뒤 어떻게 되냐 보십시요! 해보고 다시 원상태로 돌리십시요...</p> +</div> + +<div class="note"> +<p><strong>주석</strong>: 그렇습니다. 여백이 위치잡기한 요소에 여전히 영향을 미칩니다. 그러나 마진 축소 영향은 업습니다.</p> +</div> + +<div class="note"> +<p><strong>참고</strong>: 당신은 <code><a href="http://mdn.github.io/learning-area/css/css-layout/positioning/3_absolute-positioning.html">3_absolute-positioning.html</a></code>에서 예제를 확인할 수 있습니다(<a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/positioning/3_absolute-positioning.html">소스 코드를 보세요</a>).</p> +</div> + +<h3 id="위치잡기_상황">위치잡기 상황</h3> + +<p>어떤 요소가 절대 위치잡기의 기준이 되는 "콘테이너 요소"입니까? 이것은 위치잡기 요소의 조상에 지정된 위치 속성의 여하에 따라 많이 달라집니다. (See <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#Identifying_the_containing_block">콘테이너 블록 식별하기</a>).</p> + +<p>조상 요소가 명시적으로 정의된 위치 속성을 가지고 있지 않으면 초깃값으로 모든 조상 요소에 정적 위치가 부여됩니다. 그에 따른 결과, 절대적 위치잡기한 요소는 <strong>initial containing block</strong>에 포함되게 됩니다. 초기 콘테이너 블록은 브라우저 뷰포트 크기의 용적을 가지며, 자신도 {{htmlelement("html")}} 요소를 포함하는 블록입니다. 간단히 말해서, 절대적 위치잡기한 요소는 {{htmlelement("html")}} 요소의 외부에 포함되어 초기 뷰포트 기준과 비례한 곳에 위치하게 됩니다.</p> + +<p>위치잡기한 요소는 에이치티엠엘 소스의 {{htmlelement("body")}} 안에 중첩되지만 최종 조판에서는 페이지의 가장자리 상단과 왼쪽에서 30px 떨어져 있습니다. 우리는 요소의 절대적 위치잡기에서 어떤 요소에 비례해 위치잡기할지 기준이 되는 <strong>positioning context</strong>(위치잡기 상황)을 변경할 수 있습니다. 이것은 조상 요소 중 하나를 기준으로 위치잡기 설정이 이뤄집니다. 다시말해 요소의 내부에 중첩된 요소 중 하나가 기준이 됩니다(내부에 중첩되지 않은 요소를 기준삼아 비례적으로 위치시킬 수 없습니다). 이를 증명하기 위해 다음과 같은 선언을 <code>body</code> 규칙에 추가하십시요:</p> + +<pre>position: relative;</pre> + +<p>이로써 다음과 같은 결과가 나와야 합니다.</p> + +<div class="hidden"> +<pre class="brush: html"><h1>위치잡기 상황</h1> + +<p>나는 기본 볼록 수준 요소입니다. 나와 인접한 블록 수준 요소는 내 아래 새 줄에 자리합니다.</p> + +<p class="positioned">이제 나는 <code>&lt;html&gt;</code> 요소가 아닌 <code>&lt;body&gt;</code> 요소를 기준으로 비례하여 절대적 위치잡기합니다.</p> + +<p>우리는 여백으로 구분됩니다. 여백 축소로 때문에 우리의 여백 중의 하나의 너비로 구분됩니다. 두게의 여백이 아니라.</p> + +<p>인라인 요소 <span>이 것과 같은</span> 그리고 <span>이것이</span> 차례로 같은 라인에, 그리고 같은 라인에 공간이 있을 경우 인접한 텍스트 노드에 자리를 잡게 됩니다. 인라인 요소가 대열이탈할 경우 <span>(이 경우와 같이 텍스트를 포함했을 경우) 가능하면 새 줄로 접혀들어갑니다.)</span>, 그렇지 않으면 새로운 라인으로 계속 진행할 것입니다. 이 이미지가 하는 것처럼: <img src="https://mdn.mozillademos.org/files/13360/long.jpg"></p></pre> + +<pre class="brush: css">body { + width: 500px; + margin: 0 auto; + position: relative; +} + +p { + background: aqua; + border: 3px solid blue; + padding: 10px; + margin: 10px; +} + +span { + background: red; + border: 1px solid black; +} + +.positioned { + position: absolute; + background: yellow; + top: 30px; + left: 30px; +}</pre> +</div> + +<p>{{ EmbedLiveSample('위치잡기_상황', '100%', 420) }}</p> + +<p>위치잡기한 요소는 이제 기준이 되는 {{htmlelement("body")}} 요소와 비례한 위치에 놓이게 된다.</p> + +<div class="note"> +<p><strong>참고</strong>: 당신은 이 시점에 예제의 실제 구현 장면을 <code><a href="http://mdn.github.io/learning-area/css/css-layout/positioning/4_positioning-context.html">4_positioning-context.html</a></code>에서 볼 수 있습니다(<a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/positioning/4_positioning-context.html">소스 코드 보기</a>).</p> +</div> + +<h3 id="z-인덱스_소개">z-인덱스 소개</h3> + +<p>이 모든 절대적 위치잡기는 제법 재미나지만, 아직 고려하지 않은 또 다른 것이 있습니다. 요소가 겹치기 시작하면 어떤 요소가 다른 요소 위에 나타나는지 결정하는 기준은 무엇입니까? 지금까지 우리가 본 예제에서, 우리는 위치잡기 상황 속에 단 하나의 위치잡기할 요소만 주어졌습니다. 그리고 그것은 상위에 나타납니다. 왜냐면 위치잡기 요소가 비 위치잡기 요소보다 우위를 점하기 때문입니다. 하나 이상의 요소가 있을 때는 어떨까요?</p> + +<p>다음을 씨에스에스에 추가해 첫 단락도 절대적 위치잡기 대상으로 만들어 봅시다.</p> + +<pre>p:nth-of-type(1) { + position: absolute; + background: lime; + top: 10px; + right: 30px; +}</pre> + +<p>이 시점에서 당신이 보게될 것은 첫 번째 단락이 녹색으로 칠해지고, 문서 대열을 벗어나 원래 위치에서 약간 위에 자리를 잡습니다. 또한, 두 개의 단락이 겹치는 원래의 <code>.positioned</code> 클래스가 지정된 단락 아래에 겹겹이 포개집니다. 이렇게 되는 까닭은 <code>.positioned</code> 클래스로 지정된 단락이 소스 순서상에 두 번째 단락이고 소스 순서상에 뒤에 있는 위치잡기한 요소가 소스 순서상 앞서는 위치잡기한 요소보다 우위를 점하기 때문입니다.</p> + +<p>스택 순서를 변경할 수 있습니까? 네, {{cssxref("z-index")}} 속성을 사용하면 가능합니다. z-인덱스는 z축을 가리킵니다. 당신은 앞서 배경 이미지와 그림자 오프셋을 떨어뜨리는 것과 같은 사물의 위치를 파악하는 방법을 찾는 과정에서 웹 페이지를 수평(x축)과 수직(y축) 좌표로 논의한 학습 과정을 기억하실 겁니다. (0,0)은 페이지(또는 요소)의 상단 왼쪽에 있으며, x-축 및 y-축은 페이지의 오른쪽 및 아래쪽으로 진행합니다(가로쓰기 언어의 경우를 말합니다).</p> + +<p>웹 페이지에는 z축이 있습니다. 스크린 표면으로부터 진행하는 가상 라인, 즉 사용자 얼굴 쪽으로 향하는(당신이 화면 위에 놓고 싶은 것을 망론한다). {{cssxref("z-index")}} 값은 위치잡기한 요소가 해당 축상에 놓일 경우에 영향을 미칩니다. 양수 값은 스택 상단으로 이동하고 음수 값은 스택 아래로 이동합니다(역주: 상단으로 겹겹이 쌓이거나 하단으로 겹겹이 쌓여진다) 기본값으로 위치잡기한 요소는 모두 <code>z-index</code>가 <code>auto</code> 값을 가지며, 이는 사실상 0입니다.</p> + +<p>스택 순서를 변경하려면 다음 선언을 <code>p:nth-of-type(1)</code> rule: 규칙에 추가하십시오.</p> + +<pre>z-index: 1;</pre> + +<p>이제 녹색 단락이 상단에 놓여진 완성된 예가 보여야 합니다.</p> + +<div class="hidden"> +<pre class="brush: html"><h1>z-인덱스</h1> + +<p>나는 기본 볼록 수준 요소입니다. 나와 인접한 블록 수준 요소는 내 아래 새 줄에 자리합니다.</p> + +<p class="positioned">이제 나는 <code>&lt;html&gt;</code> 요소가 아닌 <code>&lt;body&gt;</code> 요소를 기준으로 비례하여 절대적 위치잡기합니다.</p> + +<p>우리는 여백으로 구분됩니다. 여백 축소로 때문에 우리의 여백 중의 하나의 너비로 구분됩니다. 두게의 여백이 아니라.</p> + +<p>인라인 요소 <span>이 것과 같은</span> 그리고 <span>이것이</span> 차례로 같은 라인에, 그리고 같은 라인에 공간이 있을 경우 인접한 텍스트 노드에 자리를 잡게 됩니다. 인라인 요소가 대열이탈할 경우 <span>(이 경우와 같이 텍스트를 포함했을 경우) 가능하면 새 줄로 접혀들어갑니다.)</span>, 그렇지 않으면 새로운 라인으로 계속 진행할 것입니다. 이 이미지가 하는 것처럼: <img src="https://mdn.mozillademos.org/files/13360/long.jpg"></p></pre> + +<pre class="brush: css">body { + width: 500px; + margin: 0 auto; + position: relative; +} + +p { + background: aqua; + border: 3px solid blue; + padding: 10px; + margin: 10px; +} + +span { + background: red; + border: 1px solid black; +} + +.positioned { + position: absolute; + background: yellow; + top: 30px; + left: 30px; +} + +p:nth-of-type(1) { + position: absolute; + background: lime; + top: 10px; + right: 30px; + z-index: 1; +} +</pre> +</div> + +<p>{{ EmbedLiveSample('z-인덱스_소개', '100%', 400) }}</p> + +<p>z-인덱스는 단위가 없는 인덱스 값만 허용한다는 점에 유의하자; 하나의 요소가 Z축 위로 23픽셀이 되도록 지정할 수 없습니다. 그런 식으론 작동하지 않습니다. 높은 값의 요소는 낮은 값 요소의 위로 간니다. 그러니 당신이 어떤 값을 사용할 지에 달려있습니다. 2와 3을 사용하면 300과 40000과 같은 효과를 얻을 수 있습니다.</p> + +<div class="note"> +<p><strong>참고</strong>: 이 시점에 예제의 실제 구현 장면을 <code><a href="http://mdn.github.io/learning-area/css/css-layout/positioning/5_z-index.html">5_z-index.html</a></code>에서 볼 수 있습니다(<a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/positioning/5_z-index.html">소스 코드 보기</a>).</p> +</div> + +<h3 id="고정_위치잡기">고정 위치잡기</h3> + +<p>이제 고정 위치잡기를 살펴보자. 이것은 절대 위치잡기와 정확히 같은 방식으로 작동합니다.단 한 가지 핵심 차이점이 있습니다. 절대 위치잡기는 {{htmlelement("html")}} 요소나 가까운 조상 요소를 기준으로 비례해 요소를 고정시키지만, 고정 위치잡기는 브라우저 뷰 포트 자체를 기준으로 비례해 요소를 고정합니다. 즉, 탐색 메뉴가 계속 자리를 지키는 것과 같이 제자리에 고정된 유용한 사용자 인터페이스 항목을 생성할 수 있습니다.</p> + +<p>우리가 무슨 얘기를 하는지 보여주기 위해 간단한 예를 들어봅시다. 먼저 씨에스에스에서 기존 <code>p:nth-of-type(1)</code>과 <code>.positioned</code> 규칙을 삭제합니다.</p> + +<p>이제 <code>position: relative;</code> 선언을 지우고, 다음과 같이 고정 높이를 추가하는 규칙을 <code>body</code> 규칙에 업데이트합니다:</p> + +<pre>body { + width: 500px; + height: 1400px; + margin: 0 auto; +}</pre> + +<p>이제 우리는 {{htmlelement("h1")}} 요소에 <code>position: fixed;</code>를 부여하고, 그걸 뷰 포트의 상단 중앙에 놓게 합니다. 다음 규칙을 씨에스에스에 추가하세요.</p> + +<pre>h1 { + position: fixed; + top: 0; + width: 500px; + margin: 0 auto; + background: white; + padding: 10px; +}</pre> + +<p>화면 상단에 고정시키려면 <code>top: 0;</code>이 요구됩니다. 그런 다음 제목에 콘텐츠 열과 동일한 너비를 부여하고 콘텐츠를 중앙에 놓기 위해 오래됐지만, 신뢰감을 주는 <code>margin: 0 auto;</code>를 사용합니다. 그런 다음 제목에 흰색 배경과 패딩을 부여해 제목 아래에 내용이 보이지 않도록 합니다.</p> + +<p>지금 저장하고 새로고침하면 제목이 고정되는 사소하지만, 재미난 효과를 볼 수 있으며, 스크롤 막대를 위로 올리면 콘텐츠가 드러나고 아래로 내리면 제목 밑으로 콘텐츠가 사라지는 것처럼 보입니다. 하지만 우리는 이것을 더 개선할 수 있습니다. 현재 일부 콘텐츠가 시작부터 제목에 밑에 깔려있는 부분 말입니다. 위치잡기한 제목이 문서 대열상에서 모습을 드러내지 않기 때문입니다. 그래서 나머지 콘텐츠가 맨 위로 이동했습니다. 우리는 올라간 것을 조금 아래로 이동시켜야 합니다. 우리는 그걸 첫 번째 단락에 최상위 여백을 설정해서 달성할 수 있습니다. 지금 다음 내용을 추가하세요:</p> + +<pre>p:nth-of-type(1) { + margin-top: 60px; +}</pre> + +<p>당신은 이제 완성된 예제를 볼 수 있어야 합니다:</p> + +<div class="hidden"> +<pre class="brush: html"><h1>고정 위치잡기</h1> + +<p>나는 기본 볼록 수준 요소입니다. 나와 인접한 블록 수준 요소는 내 아래 새 줄에 자리합니다.</p> + +<p class="positioned">나는 더 이상 특별한 위치를 차지하지 않습니다...</p> + +<p>우리는 여백으로 구분됩니다. 여백 축소로 때문에 우리의 여백 중의 하나의 너비로 구분됩니다. 두게의 여백이 아니라.</p> + +<p>인라인 요소 <span>이 것과 같은</span> 그리고 <span>이것이</span> 차례로 같은 라인에, 그리고 같은 라인에 공간이 있을 경우 인접한 텍스트 노드에 자리를 잡게 됩니다. 인라인 요소가 대열이탈할 경우 <span>(이 경우와 같이 텍스트를 포함했을 경우) 가능하면 새 줄로 접혀들어갑니다.)</span>, 그렇지 않으면 새로운 라인으로 계속 진행할 것입니다. 이 이미지가 하는 것처럼: <img src="https://mdn.mozillademos.org/files/13360/long.jpg"></p></pre> + +<pre class="brush: css">body { + width: 500px; + height: 1400px; + margin: 0 auto; +} + +p { + background: aqua; + border: 3px solid blue; + padding: 10px; + margin: 10px; +} + +span { + background: red; + border: 1px solid black; +} + +h1 { + position: fixed; + top: 0px; + width: 500px; + margin: 0 auto; + background: white; + padding: 10px; +} + +p:nth-of-type(1) { + margin-top: 60px; +}</pre> +</div> + +<p>{{ EmbedLiveSample('고정_위치잡기', '100%', 400) }}</p> + +<div class="note"> +<p><strong>참고</strong>: 당신은 이 시점에 예제의 실제 구현 장면을 <code><a href="http://mdn.github.io/learning-area/css/css-layout/positioning/6_fixed-positioning.html">6_fixed-positioning.html</a></code>에서 볼 수 있습니다 (<a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/positioning/6_fixed-positioning.html">소스 코드는 여기서 보세요</a>).</p> +</div> + +<h3 id="position_sticky">position: sticky</h3> + +<p>이용할 수 있는 <code>position: sticky</code>라고 불리우는 또 다른 위치잡기 값이 있습니다. 이것은 다른 위치잡기보다 다소 새로운 것입니다. 이것은 기본적으로 상대 위치잡기와 고정 위치잡기가 혼합된 하이브리드로서, 위치잡기 요소가 특정 임계점에(예로 뷰포트의 상단으로부터 10px) 스크롤될 때까지 상대 위치잡기처럼 행동할 수 있다가 그 뒤에 위치가 고정됩니다. 예를 들어, 탐색 막대가 특정 지점까지 페이지와 함께 스크롤한 다음 페이지 상단에 흡착되도록 사용할 수 있습니다.</p> + +<div id="흡착_1"> +<div class="hidden"> +<h6 id="흡착_위치잡기_예제">흡착 위치잡기 예제</h6> + +<pre class="brush: html"><h1>흡착 위치잡기</h1> + +<p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p> + +<div class="positioned">흡착</div> + +<p>Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut, facilisis sed est. Nam id risus quis ante semper consectetur eget aliquam lorem. Vivamus tristique elit dolor, sed pretium metus suscipit vel. Mauris ultricies lectus sed lobortis finibus. Vivamus eu urna eget velit cursus viverra quis vestibulum sem. Aliquam tincidunt eget purus in interdum. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.</p> + +<p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla luctus aliquam dolor, eu lacinia lorem placerat vulputate. Duis felis orci, pulvinar id metus ut, rutrum luctus orci. Cras porttitor imperdiet nunc, at ultricies tellus laoreet sit amet. Sed auctor cursus massa at porta. Integer ligula ipsum, tristique sit amet orci vel, viverra egestas ligula. Curabitur vehicula tellus neque, ac ornare ex malesuada et. In vitae convallis lacus. Aliquam erat volutpat. Suspendisse ac imperdiet turpis. Aenean finibus sollicitudin eros pharetra congue. Duis ornare egestas augue ut luctus. Proin blandit quam nec lacus varius commodo et a urna. Ut id ornare felis, eget fermentum sapien.</p> </pre> + +<pre class="brush: css">body { + width: 500px; + margin: 0 auto; +} + +.positioned { + background: rgba(255,84,104,.3); + border: 2px solid rgb(255,84,104); + padding: 10px; + margin: 10px; + border-radius: 5px; +}</pre> +</div> + +<pre class="brush: css">.positioned { + position: sticky; + top: 30px; + left: 30px; +}</pre> +</div> + +<p>{{ EmbedLiveSample('흡착_1', '100%', 200) }}</p> + +<p><code>position: sticky</code>의 일반적 사용례기도 하고 흥미로운 사용례는 스크롤링하다 제목에 도달하면 서로 다른 제목이 페이지의 맨 위에 흡착되는 색인 페이지를 만드는 것입니다. 이런 사례에 대한 마크업은 다음과 같은 모습일 수 있습니다:</p> + +<pre class="brush: html"><h1>흡착 위치잡기</h1> + +<dl> + <dt>A</dt> + <dd>Apple</dd> + <dd>Ant</dd> + <dd>Altimeter</dd> + <dd>Airplane</dd> + <dt>B</dt> + <dd>Bird</dd> + <dd>Buzzard</dd> + <dd>Bee</dd> + <dd>Banana</dd> + <dd>Beanstalk</dd> + <dt>C</dt> + <dd>Calculator</dd> + <dd>Cane</dd> + <dd>Camera</dd> + <dd>Camel</dd> + <dt>D</dt> + <dd>Duck</dd> + <dd>Dime</dd> + <dd>Dipstick</dd> + <dd>Drone</dd> + <dt>E</dt> + <dd>Egg</dd> + <dd>Elephant</dd> + <dd>Egret</dd> +</dl> +</pre> + +<p>씨에스에스는 다음과 같이 보일 수 있다. 일반 대열에서는 {{htmlelement("dt")}} 요소가 콘텐츠와 함께 스크롤됩니다. {{cssxref("top")}} 값이 0이고 {{htmlelement("dt")}} 요소에 <code>position: sticky</code>를 추가하면 이를 지원하는 브라우저는 그 위치(0)에 도달할 때 머리글을 브라우저 뷰포트 상단에 흡착시킵니다. 그 후 각각의 후속 머리글은 자신의 위치까지 스크롤하는 시점에 이전 머리글을 교체합니다.</p> + +<pre class="brush: css">dt { + background-color: black; + color: white; + padding: 10px; + position: sticky; + top: 0; + left: 0; + margin: 1em 0; +} +</pre> + +<div id="흡착_2"> +<div class="hidden"> +<pre class="brush: css">body { + width: 500px; + height: 1400px; + margin: 0 auto; +} + +dt { + background-color: black; + color: white; + padding: 10px; + position: sticky; + top: 0; + left: 0; + margin: 1em 0; +} +</pre> + +<pre class="brush: html"><h1>흡착 위치잡기</h1> + +<dl> + <dt>A</dt> + <dd>Apple</dd> + <dd>Ant</dd> + <dd>Altimeter</dd> + <dd>Airplane</dd> + <dt>B</dt> + <dd>Bird</dd> + <dd>Buzzard</dd> + <dd>Bee</dd> + <dd>Banana</dd> + <dd>Beanstalk</dd> + <dt>C</dt> + <dd>Calculator</dd> + <dd>Cane</dd> + <dd>Camera</dd> + <dd>Camel</dd> + <dt>D</dt> + <dd>Duck</dd> + <dd>Dime</dd> + <dd>Dipstick</dd> + <dd>Drone</dd> + <dt>E</dt> + <dd>Egg</dd> + <dd>Elephant</dd> + <dd>Egret</dd> +</dl> +</pre> +</div> +</div> + +<p>{{ EmbedLiveSample('흡착_2', '100%', 200) }}</p> + +<div class="note"> +<p><strong>참고</strong>: 당신은 이 시점에 예제의 실제 구현 장면을 <code><a href="http://mdn.github.io/learning-area/css/css-layout/positioning/7_sticky-positioning.html">7_sticky-positioning.html</a></code>에서 볼 수 있습니다(<a href="https://github.com/mdn/learning-area/blob/master/css/css-layout/positioning/7_sticky-positioning.html">소스 코드는 여기서 보세요</a>).</p> +</div> + +<h2 id="요약정리">요약정리</h2> + +<p>기본적인 위치잡기를 가지고 놀이삼아 시험해 보니 재미있었을 것이다; 비록 이것이 완전체 조판에 사용할 수 있는 방법은 아니지만, 여러분이 보았다시피 이것이 알맞은 용도로 사용될 수 있는 많은 작업들이 있다.</p> + +<p>{{PreviousMenuNext("Learn/CSS/CSS_layout/Floats", "Learn/CSS/CSS_layout/Multiple-column_Layout", "Learn/CSS/CSS_layout")}}</p> + +<h2 id="참조_항목">참조 항목</h2> + +<ul> + <li>{{cssxref("position")}} 속성 참조.</li> + <li>좀 더 유용한 구상을 위한 <a href="/ko/docs/Learn/CSS/CSS_layout/Practical_positioning_examples">실용적인 위치잡기 사례</a></li> +</ul> + +<h2 id="이번_단위에는">이번 단위에는</h2> + +<ul> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Introduction">씨에스에스 조판 소개</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/일반_흐름">일반 대열</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Flexbox">가변상자</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Grids">격자</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Floats">부동체</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/위치잡기">위치잡기</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Multiple-column_Layout">다단 조판</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/반응형_디자인">반응형 디자인</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/미디어_쿼리_초보자_안내서">미디어 쿼리 초보자 안내서</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/레거시_조판_메서드">레거시 조판 메서드</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/%EC%9D%B4%EC%A0%84_%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80_%EC%A7%80%EC%9B%90">이전 브라우저 지원</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Fundamental_Layout_Comprehension">조판 이해도 필수 평가</a></li> +</ul> diff --git a/files/ko/learn/css/css_layout/이전_브라우저_지원/index.html b/files/ko/learn/css/css_layout/이전_브라우저_지원/index.html new file mode 100644 index 0000000000..07910a4d26 --- /dev/null +++ b/files/ko/learn/css/css_layout/이전_브라우저_지원/index.html @@ -0,0 +1,248 @@ +--- +title: 이전 브라우저 지원 +slug: Learn/CSS/CSS_layout/이전_브라우저_지원 +tags: + - 가변상자 + - 격자 + - 기능 쿼리 + - 레거시 + - 부동체 + - 씨에스에스 + - 안내서 + - 조판 + - 초보자 + - 학습 +translation_of: Learn/CSS/CSS_layout/Supporting_Older_Browsers +--- +<div>{{LearnSidebar}}</div> + +<p>{{PreviousMenuNext("Learn/CSS/CSS_layout/Legacy_Layout_methods", "Learn/CSS/CSS_layout/Fundamental_Layout_Comprehension", "Learn/CSS/CSS_layout")}}</p> + +<p class="summary">이 모듈에서는 Flexbox 및 Grid를 디자인의 기본 레이아웃 메서드로 사용할 것을 권고합니다. 그러나 당신이 사용한 메서드를 지원하지 않는 브라우저나 이전 브라우저를 사용해 당신의 사이트를 방문하는 사람들이 있을 겁니다. 이런 일은 웹상에서 항상 있는 일입니다. 즉 새로운 기능이 개발됨에 따라 서로 다른 브라우저가 서로 다른 것들의 우선 순위를 정합니다. 이 문서는 구식 기술의 사용자들을 외면하지 않고도 최신 웹 기술을 사용하는 방법에 대해 설명합니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">선결 사항:</th> + <td>HTML 기본 (<a href="/ko/docs/Learn/HTML/Introduction_to_HTML">HTML 입문</a> 학습), CSS의 작동 방식 <a href="/ko/docs/Learn/CSS/Introduction_to_CSS">CSS 입문 </a> 및 (<a href="/ko/docs/Learn/CSS/Styling_boxes">상자 양식 지정</a> 학습)</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>여러분이 사용하려는 기능을 지원하지 않을 수있는 이전 브라우저에서 레이아웃을 지원하는 방법을 파악합니다.</td> + </tr> + </tbody> +</table> + +<h2 id="당신의_사이트_브라우저_지향은">당신의 사이트 브라우저 지향은?</h2> + +<p>모든 웹사이트는 공략 대상에 따라 달라집니다. 접근 방식을 결정하기 전에 이전 브라우저를 사용하여 사이트를 방문하는 방문자 수를 확인하십시오. 사람들이 사용중인 기술을 알려주는 분석 기능(예: Google analytics)을 이용할 수 있고, 추가 및 교체할 기존 웹 사이트가 있는 경우 이는 간단한 작업입니다. 당신이 분석툴이 없거나, 이번이 완전히 새로운 사이트 개설이라면 <a href="http://gs.statcounter.com/">Statcounter</a>같은 위치별로 필터링된 통계를 제공할 수 있는 사이트가 있습니다.</p> + +<p>또한 사람들이 여러분의 사이트를 이용하는 방식이나 장치 유형을 고려해야만 합니다. 예를 들어 모바일 장치 이용 방문자가 평균치를 웃돌거라는 예상을 할 수 있습니다. 접근성 및 보조 기술을 사용하는 사람들은 항상 고려해야하지만 일부 사이트에서는 그 점이 더욱 중요할 수 있습니다. 필자의 경험에 따르면 개발자들은 종종 이전 버전의 인터넷 익스플로러 사용자 1%에 대해 매우 걱정하는 반면, 더 많은 사용자 층인 내게 필요한 옵션 사용자에 대해선 전혀 고려하지 않습니다.</p> + +<h2 id="당신이_사용하려는_기능에_대한_지원은_어떻습니까">당신이 사용하려는 기능에 대한 지원은 어떻습니까?</h2> + +<p>사이트에 들어오는 브라우저를 알면, 해당 대상에 사용하고 싶은 기술을 평가할 수 있고, 그리고 그 기술을 이용할 수 없는 방문객들에게 얼마나 쉽게 대안을 제공할 수 있는지 진단할 수 있습니다. 우리는 CSS 속성을 상세히 설명하는 각 페이지에 대한 브라우저 호환성 정보를 모질라 개발자 네트워크에서 제공함으로써 쉽게 사용할 수 있도록 노력하고 있습니다. 예를 들어, {{cssxref("grid-template-columns")}} 페이지를 살펴보십시오. 이 페이지의 맨 아래에는 이 속성을 지원하기 시작한 버전과 함께 주요 브라우저가 나열된 표가 있습니다.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/16047/browser-table.png" style="height: 1178px; width: 2102px;"></p> + +<p>기능이 얼마나 잘 지원되는지 확인하는 또 다른 일반적인 방법은 <a href="https://caniuse.com/">Can I Use</a> 웹 사이트입니다. 이 사이트에는 대부분의 웹 플랫폼 기능이 브라우저 지원 상태에 대한 정보와 함께 나열됩니다. 위치별로 사용 통계를 볼 수 있습니다. 주로 특정 지역의 사용자가있는 사이트에서 작업하는 경우 유용합니다. Google 웹 로그 분석 계정을 연결하여 사용자 데이터를 기반으로 분석할 수도 있습니다.</p> + +<p>사용자의 브라우저가 보유한 기술과 당신이 사용하려는 것에 대한 지원을 이해하면 당신은 좋은 상황에서 모든 결정을 내리고 모든 사용자를 가장 잘 지원할 수있는 방법을 알 수 있습니다.</p> + +<h2 id="지원하는_것과_모양이_똑같다는_말은_다르다">지원하는 것과 '모양이 똑같다'는 말은 다르다</h2> + +<p>일부 사용자는 휴대 전화로 사이트를 보고 다른 사용자는 대형 데스크톱 화면에서 사이트를 보고 있기 때문에 모든 브라우저에서 웹 사이트가 동일하게 보이지 않을 수 있습니다. 마찬가지로 일부 사용자는 이전 브라우저 버전을 갖고 있고 다른 사용자에게는 최신 브라우저를 갖고 있습니다. 일부 사용자는 화면 읽기 프로그램을 사용해 내용을 읽거나 페이지를 확대하여 읽을 수도 있습니다. 모든 사람을 지원한다는 것은 방어적으로 디자인된 콘텐츠 버전을 제공하여 최신 브라우저에서는 사이트 외관이 뛰어나지만, 이전 브라우저 사용자에게는 기본 수준으로 계속 사용할 수 있음을 의미합니다.</p> + +<p>기본적인 지원 수준이란 페이지의 일반적인 흐름이 이해되도록 콘텐츠를 잘 구성하는 것에서 출발합니다. 기능이 매우 제한적인 전화기 사용자는 많은 CSS를 얻을 수 없지만, 콘텐츠는 쉽게 읽을 수 있는 방식으로 나열됩니다. 따라서 항상 잘 구성된 HTML 문서에서 출발해야 합니다. 여러분의 스타일 시트를 제거했을 때, 컨텐츠가 여전히 잘 이해되나요?</p> + +<p>한 가지 옵션은 아주 오래된 브라우저나 제한된 브라우저를 사용하는 사람들이 찾을 수 있는 대체 페이지로 사이트 외관을 단순화하는 것입니다. 문제가 되는 해당 브라우저를 사용해 소수의 사람들이 사이트를 방문하는 경우 최신 브라우저 사용자들과 비슷한 체험을 그들에게 제공하기 위해 시간을 쏟는 것이 상업적으로 맞지 않을 겁니다. 사이트의 접근성을 높이고 더 많은 사용자에게 서비스를 제공하는 일에 시간을 투자하는 것이 더 좋을 겁니다. 평범한 HTML 페이지와 온갖 장신구가 포함된 페이지 사이에는 중간 지점이 있으며 CSS는 실제로 이러한 대체 페이지를 매우 간단하게 생성해 줍니다.</p> + +<h2 id="CSS로_대체_페이지_생성하기">CSS로 대체 페이지 생성하기</h2> + +<p>CSS 규격에는 두 가지 레이아웃 메서드가 동일한 항목에 적용될 때 브라우저가 수행하는 작업을 설명하는 정보가 포함되어 있습니다. 즉, 부동체 항목이 한편으로는 CSS grid 레이아웃을 사용하는 grid 항목인 경우 발생하는 상황에 대한 정의가 있음을 의미합니다. 이 정보가 브라우저가 이해하지 못하는 CSS를 무시한다는 지식과 결합되어, 이미 다루었던 <a href="/ko/docs/Learn/CSS/CSS_layout/레거시_조판_메서드">레거시 기술</a>을 사용하여 간단한 레이아웃을 생성할 수 있는 방법이 있습니다. 그런 다음 이를 최신 브라우저에서는 grid 레이아웃으로 덮어씁니다.</p> + +<p>아래 예에서는 세 개의 <code><div></code> 부동체를 행으로 표시했습니다. <a href="/ko/docs/Learn/CSS/CSS_layout/Grids">CSS grid 레이아웃</a>을 지원하지 않는 브라우저는 상자 행을 <ruby><em>부동 레이아웃</em><rp> (</rp><rt>浮動 組版</rt><rp>) </rp></ruby>으로 간주합니다. grid 항목이 되는 부동 항목은 부동 동작을 상실합니다. 즉, <code>.wrapper</code> 클레스를 grid 컨테이너로 전환하면 부동 항목이 grid 항목이 됩니다. 브라우저가 grid 레이아웃을 지원하는 경우 grid 디스플레이를 표시합니다. 지원하지 않으면 <code>display: grid</code> 관련 속성은 무시되고 부동 레이아웃이 사용됩니다.</p> + +<div id="예제1"> +<pre class="brush: css">* {box-sizing: border-box;} + +.wrapper { + background-color: rgb(79,185,227); + padding: 10px; + max-width: 400px; + display: grid; + grid-template-columns: 1fr 1fr 1fr; +} + +.item { + float: left; + border-radius: 5px; + background-color: rgb(207,232,220); + padding: 1em; +} +</pre> + +<pre class="brush: html"><div class="wrapper"> + <div class="item">항목 하나</div> + <div class="item">항목 둘</div> + <div class="item">항목 셋</div> +</div> +</pre> + +<p>{{ EmbedLiveSample('예제1', '100%', '200') }}</p> +</div> + +<div class="note"> +<p><strong>참고</strong>: {{cssxref("clear")}} 속성도 마찬가지로 정리된 항목이 grid가 되자마자 효력을 상실합니다. 따라서 정리된 footer가 딸린 레이아웃을 가질 수 있으며, 이 레이아웃이 grid 레이아웃으로 전환됩니다.</p> +</div> + +<h3 id="대체_메서드">대체 메서드</h3> + +<p>이 부동 예제와 비슷한 방식으로 사용할 수있는 여러 레이아웃 메서드가 있습니다. 당신이 생성해야하는 레이아웃 패턴에 가장 적합한 것을 선택할 수 있습니다.</p> + +<dl> + <dd>Float(부동) 및 <strong>clear</strong></dd> + <dd>위에서 볼 수 있듯이, 부동 또는 정리 속성이 레이아웃에 미치는 효과는 부동되거나 정리된 항목이 flex 또는 grid 항목이 되면 중단됩니다.</dd> + <dt>display: inline-block</dt> + <dd>이 방법을 사용하여 열 레이아웃을 생성할 수 있는 경우는 항목이 <code>display: inline-block</code>로 설정되었을 경우이지만, flex 또는 grid 항목이 된다면 인라인 블록 동작은 무시됩니다.</dd> + <dt>display: table</dt> + <dd>CSS 테이블을 생성하는 메서드는 해당 단원의 <a href="/ko/docs/Learn/CSS/CSS_layout/Introduction">입문서</a>가 대체품으로 활용될 수 있습니다. CSS 테이블 레이아웃으로 설정된 항목은 그들이 flex 또는 grid 항목이 될 경우 자기 동작을 상실하게 됩니다. 중요하게는 테이블 구조를 수정하기 위해 생성된 익명 상자는 생성되지 않습니다.</dd> + <dt>다단 레이아웃</dt> + <dd>특정 레이아웃의 경우 당신은 <a href="/ko/docs/Learn/CSS/CSS_layout/Multiple-column_Layout">다단</a>을 대체품로 사용할 수 있습니다. 여러분의 콘테이너가 <code>column-*</code> 속성에 속한 것으로 정의되었다면 grid 컨테이너가 될 것이고, 다단 동작은 발생하지 않습니다.</dd> + <dt>grid 대체품 역할인 Flexbox</dt> + <dd><a href="/en-US/docs/Learn/CSS/CSS_layout/Flexbox">Flexbox</a>는 인터넷 익스플로러 10과 11이 지원하기 때문에 grid를 지원하는 브라우저가 훨씬 많이 있습니다. 다만 이 단원의 뒷부분에서 설명하고 있는 구형 브라우저에서 flex를 지원하기 위한 처리 방법에 대해서도 확인해보세요. flex 컨테이너를 grid 컨테이너로 만들면 자식에 적용된 모든 <ruby><code>flex</code><rp> (</rp><rp>) </rp></ruby> 속성은 무시됩니다.</dd> +</dl> + +<p>구형 브라우저에서 레이아웃 조정이 많이 필요한 경우 CSS를 이런 식으로 사용하면 괜찮은 경험을 할 수 있습니다. 오래되고 잘 지원되는 기술을 기반으로 간단한 레이아웃을 추가한 다음 최신 CSS를 사용하여 잠재 고객의 90% 이상이 볼 수있는 레이아웃을 만듭니다. 그러나 대체 코드에 새 브라우저가 해석할 내용이 포함되어야하는 경우가 있습니다. 이에 대한 좋은 예는 부동 항목에 백분율 너비를 추가하여 열을 마치 grid 디스플레이처럼 보이도록 컨테이너를 채울 수 있도록 (너비를) 늘리는 경우입니다.</p> + +<p>부동 레이아웃에서 백분율은 컨테이너를 기준으로 계산됩니다. 33.333%는 컨테이너 너비의 3 분의 1입니다. 그러나 grid에서는 항목이 배치된 grid 영역을 기준으로 33.333%가 계산되므로 grid 레이아웃이 도입되면 실제로 원하는 크기의 3분의 1이 됩니다.</p> + +<div id="예제2"> +<pre class="brush: css">* {box-sizing: border-box;} + +.wrapper { + background-color: rgb(79,185,227); + padding: 10px; + max-width: 400px; + display: grid; + grid-template-columns: 1fr 1fr 1fr; +} + +.item { + float: left; + border-radius: 5px; + background-color: rgb(207,232,220); + padding: 1em; + width: 33.333%; +} +</pre> + +<pre class="brush: html"><div class="wrapper"> + <div class="item">항목 하나</div> + <div class="item">항목 둘</div> + <div class="item">항목 셋</div> +</div> +</pre> + +<p>{{ EmbedLiveSample('예제2', '100%', '200') }}</p> +</div> + +<p>이 문제를 해결하려면 grid가 지원되는지 여부와 너비가 재정의되는지 여부를 감지할 수있는 방법이 필요합니다. CSS가 우리를 위해 마련한 해결책은 이렇습니다.</p> + +<h2 id="Feature_queries">Feature queries</h2> + +<p>feature queries를 사용하면 브라우저가 특정 CSS 기능을 지원하는지 테스트 할 수 있습니다. 즉, 특정 기능을 지원하지 않는 브라우저 용 CSS를 작성한 다음 브라우저가 지원되는지 여부와 멋진 레이아웃을 제공하는지 확인하십시오.</p> + +<p>위의 예제에 feature query를 추가하면 grid가 지원됨을 알고 있는 경우 이 feature query를 사용하여 항목 너비를 <ruby><code>auto</code><rp> (</rp><rp>) </rp></ruby>으로 다시 설정할 수 있습니다.</p> + +<div id="예제3"> +<pre class="brush: css">* {box-sizing: border-box;} + +.wrapper { + background-color: rgb(79,185,227); + padding: 10px; + max-width: 400px; + display: grid; + grid-template-columns: 1fr 1fr 1fr; +} + +.item { + float: left; + border-radius: 5px; + background-color: rgb(207,232,220); + padding: 1em; + width: 33.333%; +} + +@supports (display: grid) { + .item { + width: auto; + } +} +</pre> + +<pre class="brush: html"><div class="wrapper"> + <div class="item">항목 하나</div> + <div class="item">항목 둘</div> + <div class="item">항목 셋</div> +</div> +</pre> + +<p>{{ EmbedLiveSample('예제3', '100%', '200') }}</p> +</div> + +<p>feature query에 대한 지원은 최신 브라우저에서 매우 유용하지만 CSS grid를 지원하지 않는 브라우저는 feature query도 지원하지 않는다는 점에 유의해야합니다. 이는 위에서 설명한 접근 방식이 해당 브라우저에서 작동한다는 것을 의미합니다. 우리가 하는 작업은 feature query를 차치하고 먼저 이전 CSS를 작성하는 것입니다. grid를 지원하지 않고 feature query를 지원하지 않는 브라우저는 자기가 이해할 수 있는 레이아웃 정보를 이용하고 그밖에 다른 것들은 완전히 무시할 수 있습니다. feature query를 지원하는 브라우저는 CSS grid도 지원하므로 grid 코드 및 feature query 내부의 코드를 실행합니다.</p> + +<p>feature query 규격에는 브라우저가 기능을 지원하지 않는지 테스트하는 기능도 포함되어 있습니다. 이는 브라우저가 feature query를 지원하는 경우에만 유용합니다. feature query를 지원하지 않는 브라우저가 갈수록 사라짐에 따라 미래에는 지원 부족 여부를 확인하는 방법은 작동하게 됩니다. 그러나 지금은 최상의 지원을 위해 이전 CSS를 사용한 다음 덮어 쓰는 방식을 사용하십시오.</p> + +<h2 id="Flexbox_예전_버전">Flexbox 예전 버전</h2> + +<p>이전 버전의 브라우저에서는 이전의 Flexbox 명세가 반복되는 것을 여러분은 발견할 수 있습니다. 글을 쓰는 시점에서 이것은 Flexbox에 <code>-ms-</code> 접두사를 사용하는 인터넷 익스플로러 10의 문제입니다. 이는 또한 오래된 문서와 자습서가 있음을 의미합니다. 이 유용한 <a href="https://css-tricks.com/old-flexbox-and-new-flexbox/">안내서</a>는 보고있는 내용을 확인하는 데 도움이되고 매우 오래된 브라우저에서 flex 지원이 필요한 경우에도 도움이 될 수 있습니다.</p> + +<h2 id="인터넷_익스플로러_10과_11_접두사_버전">인터넷 익스플로러 10과 11 접두사 버전</h2> + +<p>CSS grid 규격은 인터넷 익스플로러 10에서 처음 나온 원형이었습니다. 즉, 인터넷 익스플로러 10 및 11에는 최신 grid 지원이 없지만, 이 사이트에 문서화된 최신 규격과는 다르나 매우 유용한 그리드 레이아웃 버전이 있습니다. 인터넷 익스플로러 10 및 11 구현은 <code>-ms-</code> 접두사를 사용해 해당 그리드를 마이크로소프트 브라우저에 사용할 수 있으며 이외의 브라우저에서는 무시됩니다. 에지 브라우저는 여전히 이전 구문을 이해하므로 현대 그리드 CSS에서 모든 항목을 안전하게 덮어씁니다.</p> + +<p><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/CSS_Grid_and_Progressive_Enhancement">그리드 레이아웃의 점진적 향상</a>에 대한 안내서는 그리드의 인터넷 익스플로러 버전을 이해하는 데 도움이되며 이 단원 끝에는 별도의 유용한 링크를 포함하고 있습니다. 그러나 이전 인터넷 익스플로러 버전 사용자의 방문자 수가 매우 많지 않다면 모든 비지원 브라우저에서 작동하는 대체품을 만드는 것이 더 좋습니다.</p> + +<h2 id="이전_브라우저_여부_확인">이전 브라우저 여부 확인</h2> + +<p>Flexbox 및 그리드를 지원하는 대부분의 브라우저를 사용하면 구형 브라우저를 테스트하기가 상당히 어려울 수 있습니다. 한 가지 방법은 <a href="https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing">크로스 브라우저 테스트</a> 단위에 설명 된대로 Sauce<em> Labs</em>과 같은 온라인 테스트 도구를 사용하는 것입니다.</p> + +<p>또한 가상 컴퓨터를 다운로드하여 설치한 뒤 제약이 걸린 본인의 컴퓨터 환경에서 이전 버전의 브라우저를 실행할 수 있습니다. 이전 버전의 인터넷 익스플로러에 액세스하는 것이 특히 유용하며 이를 위해 마이크로소프트는 <a href="https://developer.microsoft.com/en-us/microsoft-edge/tools/vms/">다양한 가상 컴퓨터를 무료로 다운로드</a> 할 수 있도록 만들었습니다. 맥, 윈도우즈 및 리눅스 운영 체제에서 가상 컴퓨터를 사용할 수 있으므로 윈도우즈 컴퓨터를 사용하지 않더라도 이전 및 최신 윈도우즈 브라우저에서 테스트할 수있는 좋은 방법입니다.</p> + +<h2 id="요약정리">요약정리</h2> + +<p>여러분은 이제 그리드 및 Flexbox와 같은 기술을 자신있게 사용하고, 이전 브라우저를 위한 대체품을 만들고, 향후 발생할 수 있는 새로운 기술을 활용할 수 있는 지식을 얻었습니다.</p> + +<h2 id="참조_항목">참조 항목</h2> + +<ul> + <li><a href="https://hacks.mozilla.org/2016/08/using-feature-queries-in-css/">CSS feature query 사용하기</a></li> + <li><a href="https://developer.mozilla.org/ko/docs/Web/CSS/CSS_Flexible_Box_Layout/Backwards_Compatibility_of_Flexbox">Flexbox의 이전 버전과의 호환성</a></li> + <li><a href="https://developer.mozilla.org/ko/docs/Web/CSS/CSS_Grid_Layout/CSS_Grid_and_Progressive_Enhancement">CSS 레이아웃과 점진적 향상</a></li> + <li><a href="https://www.smashingmagazine.com/2017/11/css-grid-supporting-browsers-without-grid/">CSS 그리드 사용하기: 그리드 없는 브라우저 지원하기</a></li> + <li><a href="https://24ways.org/2012/css3-grid-layout/">인터넷 익스플로러 10 및 11 버전 그리드 사용을 위한 자습서</a></li> + <li><a href="https://rachelandrew.co.uk/archives/2016/11/26/should-i-try-to-use-the-ie-implementation-of-css-grid-layout/">인터넷 익스플로러 10 용 그리드 레이아웃 구현을 사용해야 하나요</a>?</li> + <li><a href="https://24ways.org/2017/cascading-web-design/">feature query가 포함된 중첩된 웹 디자인</a></li> + <li><a href="https://gridbyexample.com/learn/2016/12/24/learning-grid-day24/">feature query 사용하기 (동영상)</a></li> +</ul> + +<p>{{PreviousMenuNext("Learn/CSS/CSS_layout/Legacy_Layout_methods", "Learn/CSS/CSS_layout/Fundamental_Layout_Comprehension", "Learn/CSS/CSS_layout")}}</p> + +<h2 id="이번_단위에는">이번 단위에는</h2> + +<ul> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Introduction">CSS 레이아웃 소개</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/일반_흐름">Normal Flow</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Flexbox">Flexbox</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Grids">그리드</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Floats">부동체</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/위치잡기">위치잡기</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Multiple-column_Layout">다단 레이아웃</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/반응형_디자인">반응형 디자인</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/미디어_쿼리_초보자_안내서">미디어 쿼리 초보자 안내서</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/레거시_조판_메서드">레거시 레이아웃 메서드</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/%EC%9D%B4%EC%A0%84_%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80_%EC%A7%80%EC%9B%90">이전 브라우저 지원</a></li> + <li>레이아웃 이해도 필수 평가</li> +</ul> diff --git a/files/ko/learn/css/css_layout/일반_흐름/index.html b/files/ko/learn/css/css_layout/일반_흐름/index.html new file mode 100644 index 0000000000..43b4366c0e --- /dev/null +++ b/files/ko/learn/css/css_layout/일반_흐름/index.html @@ -0,0 +1,102 @@ +--- +title: 일반 대열 +slug: Learn/CSS/CSS_layout/일반_흐름 +tags: + - 격자형 + - 부동 + - 씨에스에스 + - 일반 대열 + - 조판 + - 초보자 + - 학습 +translation_of: Learn/CSS/CSS_layout/Normal_Flow +--- +<div>{{LearnSidebar}}</div> + +<p>{{PreviousMenuNext("Learn/CSS/CSS_layout/Introduction", "Learn/CSS/CSS_layout/Flexbox", "Learn/CSS/CSS_layout")}}</p> + +<p class="summary">이번 글에서는 normal flow, 다른 말로 만일 당신이 요소의 레이아웃을 변경하지 않을 시 웹페이지 요소가 자기 자신을 배치하는 방법에 관해 설명합니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">선결 사항:</th> + <td>HTML의 기초 (<a href="/ko/docs/Learn/HTML/Introduction_to_HTML">HTML에 대한 소개</a>)와 CSS 작동 방식에 대한 개념(<a href="/en-US/docs/Learn/CSS/Introduction_to_CSS">CSS 소개</a>를 공부하세요.)</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>변경이 이뤄지기 전에 브라우저가 웹 페이지를 기본값으로 레이아웃하는 방법을 설명하기</td> + </tr> + </tbody> +</table> + +<p>이전 단원에서 상세히 기술한 바와 같이, 당신이 CSS를 적용하지 않을 경우 웹 페이지의 요소는 normal flow로 배치됩니다. 그리고 normal flow에 포함된 요소의 위치를 조정하거나 요소를 완전히 제거함으로써 요소가 동작하는 방법을 변경할 수 있습니다. 모든 웹 페이지를 시작하는 최상의 방법은 normal flow에서 읽기 가능하며, 견고하고 구조화된 문서로 시작하는 것입니다. 이렇게 하면 제한된 기능을 가진 브라우저를 사용하거나 페이지 콘텐츠를 소리 내 읽는 스크린 리더와 같은 장치를 사용하는 사용자들까지 읽을 수 있는(readable) 콘텐츠로 만들 수 있습니다. 또한, normal flow는 읽기 가능한 문서를 만들도록 마련된 것으로, 이를 출발점으로 삼아 레이아웃을 변경할 때 웹페이지 문서와 대립해 싸울 게 아니라 그것과 협력해서 작업하게 됩니다.</p> + +<p>서로 다른 레이아웃 메서드를 본격적으로 파헤치기 전에 일반 문서 흐름과 관련하여 이전 모듈에서 학습했던 내용 중의 일부를 복습하는 것도 가치가 있습니다.</p> + +<h2 id="기본값으로_요소들은_어떻게_배치되는가">기본값으로 요소들은 어떻게 배치되는가?</h2> + +<p>우선 개별 요소인 상자의 배치는 자신의 내용물을 채택하고, 그 주변에 패딩을 더하고, 테두리와 여백을 더하는 식으로 이뤄집니다. 다시 말해 앞서 살펴보았던 박스 모델과 같습니다.</p> + +<p>기본값으로 <a href="/ko/docs/Web/HTML/Block-level_elements">블록 수준 요소</a>의 내용물은 자기 부모 요소의 너비 100%와 자체 내용물의 최대 높이가 됩니다. <a href="/ko/docs/Web/HTML/Inline_elements">인라인 요소</a>는 자체 내용물의 최대 높이를 취하는 동시에 최대 너비를 취합니다. 인라인 요소에 너비나 높이를 설정할 수는 없습니다. 그들은 블록 수준 요소의 콘텐츠 내부에 들어앉았을 뿐입니다. 인라인 요소의 크기를 제어하려면 그것을 <code>display: block;</code> 속성값이나 양쪽의 성격이 혼합된 <code>display: inline-block;</code>을 가지고 블록 수준 요소처럼 행동하도록 설정할 필요가 있습니다.</p> + +<p>앞서 살펴본 내용에서 개별 요소는 설명되지만, 여러 요소가 서로 상호 작용하는 방법은 어떻게 설명할까요? (레이아웃 입문서에서 언급했던) 일반 레이아웃의 flow는 브라우저의 뷰포트 안에 요소를 배치하는 시스템입니다. 기본값으로 블록 수준 요소의 배치는 부모의 <a href="/ko/docs/Web/CSS/writing-mode">쓰기 모드</a>(<em>initial</em>: horizontal-tb)에 기초해 <em>블록 flow 방향</em>에 포함되어 이뤄집니다. 다시 말해 각 블록 요소는 마지막 요소 아래 새 줄에 나타나며, 각 요소에 주어진 margin에 의해 구분됩니다. 그러므로 영어 또는 여타 가로쓰기, 상단에서 하단으로 행갈이 하는 쓰기 모드와 블록 수준 요소는 수직으로 배치됩니다.</p> + +<p>인라인 요소는 다르게 동작합니다. 새로운 줄에 나타나는 대신, 다른 요소와 같은 라인에 차례로 자리 잡습니다. 다만 인접(혹은 접힌) 텍스트 콘텐츠는 해당 부모의 블록 수준 요소의 너비 내에서 자신이 자리를 잡을 수 있는 공간이 있는 경우가 해당합니다. 충분한 공간이 없을 경우 overflow되는 텍스트 또는 요소는 새로운 줄에 나타납니다.</p> + +<p>두 개의 인접 요소가 모두 자체 여백이 지정되어 있다면 두 여백은 접촉하고 그중 큰 여백만 남게 되며, 작은 여백은 사라집니다. 이를 마진 축소(margin collapsing)라고 하며 이전에 확인해본 적이 있습니다.</p> + +<p>이 모든 것을 설명하는 간단한 예를 살펴봅시다.</p> + +<div id="일반_대열"> +<pre class="brush: html"><h1>기본 문서 flow</h1> + +<p>나는 기본 볼록 수준 요소입니다. 나와 인접한 블록 수준 요소는 내 아래 새 줄에 자리합니다.</p> + +<p>기본값으로 우리는 우리 부모 요소의 너비 100%를 넘나들며, 우리 자녀 콘텐츠의 최대 높이를 취합니다. 우리의 총 너비와 총 높이는 우리의 콘텐츠 + 패딩 + 테두리 너비 및 높이입니다.</p> + +<p>우리는 여백으로 구분됩니다. 여백 축소로 때문에 우리의 여백 중의 하나의 너비로 구분됩니다. 두게의 여백이 아니라.</p> + +<p>인라인 요소 <span>이 것과 같은</span> 그리고 <span>이것이</span> 차례로 같은 라인에, 그리고 같은 라인에 공간이 있을 경우 인접한 텍스트 노드에 자리를 잡게 됩니다. 인라인 요소가 오버플로할 경우 <span>(이 경우와 같이 텍스트를 포함했을 경우) 가능하면 새 줄로 접혀들어갑니다.)</span>, 그렇지 않으면 새로운 라인으로 계속 진행할 것입니다. 이 이미지가 하는 것처럼: <img src="https://mdn.mozillademos.org/files/13360/long.jpg"></p></pre> + +<pre class="brush: css">body { + width: 500px; + margin: 0 auto; +} + +p { + background: rgba(255,84,104,0.3); + border: 2px solid rgb(255,84,104); + padding: 10px; + margin: 10px; +} + +span { + background: white; + border: 1px solid black; +}</pre> +</div> + +<p>{{ EmbedLiveSample('일반_flow', '100%', 500) }}</p> + +<h2 id="요약정리">요약정리</h2> + +<p>이제 당신은 normal flow은 물론, 기본값으로 브라우저가 어떤 방식으로 사물을 배치하는지 이해했습니다. 당신의 디자인 필요에 따라 레이아웃을 만들기 위해 디스플레이 기본값을 변경하는 방법을 배우려면 다음 단계로 이동하세요.</p> + +<p>{{PreviousMenuNext("Learn/CSS/CSS_layout/Introduction", "Learn/CSS/CSS_layout/Flexbox", "Learn/CSS/CSS_layout")}}</p> + +<h2 id="이번_단위에는">이번 단위에는</h2> + +<ul> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Introduction">CSS 레이아웃 입문서</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/%EC%9D%BC%EB%B0%98_%ED%9D%90%EB%A6%84">normal flow</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Flexbox">가변상자</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Grids">격자</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Floats">부동체</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/%EC%9C%84%EC%B9%98%EC%9E%A1%EA%B8%B0">위치잡기</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Multiple-column_Layout">다단 레이아웃</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/%EB%B0%98%EC%9D%91%ED%98%95_%EB%94%94%EC%9E%90%EC%9D%B8">반응형 디자인</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/Legacy_Layout_Methods">레거시 레이아웃 메서드</a></li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout/%EC%9D%B4%EC%A0%84_%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80_%EC%A7%80%EC%9B%90">이전 브라우저 지원</a></li> + <li>필수 레이아웃 이해도 평가</li> +</ul> diff --git a/files/ko/learn/css/first_steps/getting_started/index.html b/files/ko/learn/css/first_steps/getting_started/index.html new file mode 100644 index 0000000000..431e4bca1a --- /dev/null +++ b/files/ko/learn/css/first_steps/getting_started/index.html @@ -0,0 +1,253 @@ +--- +title: CSS 로 시작하기 +slug: Learn/CSS/First_steps/Getting_started +translation_of: Learn/CSS/First_steps/Getting_started +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/CSS/First_steps/What_is_CSS", "Learn/CSS/First_steps/How_CSS_is_structured", "Learn/CSS/First_steps")}}</div> + +<p class="summary">이 기사에서는 간단한 HTML 문서를 가져와서 CSS 를 적용하여 언어에 대한 실질적인 내용을 학습합니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">전제조건:</th> + <td>기본 컴퓨터 활용 능력, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Installing_basic_software">기본 소프트웨어 설치</a>, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Dealing_with_files">파일 작업</a> 에 대한 기본 지식 및 HTML 기본 지식 (<a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">HTML 소개</a> 학습)</td> + </tr> + <tr> + <th scope="row">목적:</th> + <td>CSS 문서를 HTML 파일에 연결하는 기본 사항을 이해하고, CSS를 사용하여 간단한 텍스트 형식을 지정하기</td> + </tr> + </tbody> +</table> + +<h2 id="HTML_로_시작합니다">HTML 로 시작합니다</h2> + +<p>시작점은 HTML 문서입니다. 자신의 컴퓨터에서 작업하려는 경우에는 아래에서 코드를 복사할 수 있습니다. 아래 코드를 컴퓨터의 폴더에 <code>index.html</code> 로 저장하십시오.</p> + +<pre class="brush: html"><!doctype html> +<html lang="ko-KR"> +<head> + <meta charset="utf-8"> + <title>CSS로 시작하기</title> +</head> + +<body> + + <h1>레벨 1 제목입니다</h1> + + <p>이것은 단락입니다. 본문에는 <span>span 요소</span>와 <a href="http://example.com">링크</a>가 있습니다.</p> + + <p>이것은 두 번째 단락입니다. <em>강조된</em> 요소를 포함합니다.</p> + + <ul> + <li>항목 하나</li> + <li>항목 둘</li> + <li>항목 <em>셋</em></li> + </ul> + +</body> + +</html> +</pre> + +<div class="blockIndicator note"> +<p><strong>참고</strong>: 파일을 쉽게 만들 수 없는 장치나 환경에서 이 내용을 읽는 경우, 걱정하지 마십시오 — 페이지의 바로 여기에 예제 코드를 작성할 수 있도록 라이브 코드 편집기가 제공됩니다.</p> +</div> + +<h2 id="문서에_CSS_추가하기">문서에 CSS 추가하기</h2> + +<p>가장 먼저 해야할 일은 HTML 문서에 사용하려는 CSS 규칙이 있다는 것을 알리는 것입니다. CSS 를 HTML 문서에 적용하는 방법에는 세 가지가 있지만, 지금은 문서의 head 에서 연결하는 가장 일반적이고 유용한 방법을 살펴 보겠습니다.</p> + +<p>HTML 문서와 같은 폴더에 파일을 만들고 <code>styles.css</code> 로 저장하십시오. <code>.css</code> 확장자는 이것이 CSS 파일임을 보여줍니다.</p> + +<p><code>styles.css</code> 파일을 <code>index.html</code> 에 링크하려면, HTML 문서의 {{htmlelement("head")}} 안에 다음 행을 추가하십시오:</p> + +<pre class="brush: html"><link rel="stylesheet" href="styles.css"></pre> + +<p>이 {{htmlelement("link")}} 요소는 <code>rel</code> 속성을 사용하는 스타일 시트와 해당 스타일 시트의 위치를 <code>href</code> 속성의 값으로 브라우저에게 알려줍니다. <code>styles.css</code> 에 규칙을 추가하여 CSS 가 작동하는지 테스트 할 수 있습니다. 코드 편집기를 사용하여 CSS 파일에 다음을 추가하십시오:</p> + +<pre class="brush: css">h1 { + color: red; +}</pre> + +<p>HTML 및 CSS 파일을 저장하고 웹 브라우저에서 페이지를 다시 로드 하십시오. 문서 상단의 레벨 1 제목이 이제 빨간색이어야 합니다. 이 경우 축하합니다. 일부 CSS 를 HTML 문서에 성공적으로 적용했습니다. 그렇지 않으면 모든 것을 올바르게 입력했는지 주의 깊게 확인하십시오.</p> + +<p><code>styles.css</code> 에서 로컬로 계속 작업하거나, 아래의 대화식 편집기를 사용하여 이 자습서를 계속할 수 있습니다. 대화식 편집기는 위의 문서와 마찬가지로 첫 번째 패널의 CSS가 HTML 문서에 연결된 것처럼 작동합니다.</p> + +<h2 id="HTML_요소_스타일링">HTML 요소 스타일링</h2> + +<p>제목을 빨간색으로 하여 이미 HTML 요소를 대상으로 스타일을 지정할 수 있음을 보여주었습니다. 이 작업은 요소 선택자 (HTML 요소 이름과 직접 일치하는 선택자) 를 대상으로 수행됩니다. 문서의 모든 단락을 대상으로 하려면 선택자 <code>p</code> 를 사용합니다. 모든 단락을 녹색으로 바꾸려면 다음을 사용하십시오:</p> + +<pre class="brush: css">p { + color: green; +}</pre> + +<p>선택자를 쉼표로 구분하여 여러 선택자를 한 번에 대상으로 지정할 수 있습니다. 모든 단락과 모든 목록 항목을 녹색으로 만들려면 규칙은 다음과 같습니다:</p> + +<pre class="brush: css">p, li { + color: green; +}</pre> + +<p>아래의 대화식 편집기 (코드 박스 편집) 또는 로컬 CSS 문서에서 이를 시도하십시오.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/getting-started/started1.html", '100%', 900)}} </p> + +<h2 id="요소_elements_의_기본_동작_변경하기">요소 (elements) 의 기본 동작 변경하기</h2> + +<p>예제와 같이 간단한 HTML 문서를 살펴보면, 기본 스타일을 추가하여 브라우저가 HTML을 읽을 수 있게 만드는 방법을 알 수 있습니다. 제목은 크고 대담하며 목록에는 글머리 기호가 있습니다. 이는 브라우저에서 기본 스타일을 포함하는 내부 스타일 시트가 있기 때문에 기본적으로 모든 페이지에 적용됩니다. 그들 없이는 모든 텍스트가 한 덩어리로 모여서 처음부터 모든 것을 스타일링 해야합니다. 모든 최신 브라우저는 기본적으로 HTML 내용을 거의 같은 방식으로 표시합니다.</p> + +<p>그러나, 종종 브라우저에서 선택한 것 이외의 것을 원할 것입니다. 변경하려는 HTML 요소를 선택하고 CSS 규칙을 사용하여 모양을 변경하면 됩니다. 좋은 예는 순서가 없는 목록인 <code><ul></code> 입니다. 목록 글머리 기호가 있으며, 그 글머리 기호를 원하지 않으면 다음과 같이 제거할 수 있습니다:</p> + +<pre class="brush: css">li { + list-style-type: none; +}</pre> + +<p>이것을 CSS 에 추가하십시오.</p> + +<p><code>list-style-type</code> 속성은 MDN 에서 지원되는 값을 확인하는 데 유용한 속성입니다. <code><a href="/en-US/docs/Web/CSS/list-style-type">list-style-type</a></code> 에 대한 페이지를 살펴보면 페이지 상단에 몇 가지 다른 값을 시도하는 대화식 예제가 있으며, 허용 가능한 모든 값이 페이지 아래에 자세히 나와 있습니다.</p> + +<p>이 페이지를 보면 목록 글머리 기호를 제거할 뿐만 아니라 목록 글머리 기호를 변경할 수 있음을 알 수 있습니다. <code>square</code> 값을 사용하여 정사각형 글머리 기호로 변경하십시오.</p> + +<h2 id="class_추가하기">class 추가하기</h2> + +<p>지금까지 HTML 요소 이름을 기반으로 요소의 스타일을 지정했습니다. 문서에서 해당 유형의 모든 요소가 동일하게 표시되기를 원하는 한 작동합니다. 대부분의 경우에 해당되지 않으므로 다른 요소를 변경하지 않고 요소의 하위 부분을 선택할 수 있는 방법을 찾아야 합니다. 이를 수행하는 가장 일반적인 방법은 HTML 요소에 class 를 추가하고 해당 class 를 대상으로 하는 것입니다.</p> + +<p>HTML 문서에서, 두 번째 목록 항목에 <a href="/en-US/docs/Web/HTML/Global_attributes/class">class 속성</a> 을 추가하십시오. 이제 목록은 다음과 같습니다:</p> + +<pre class="brush: html"><ul> + <li>항목 하나</li> + <li <strong>class="special"</strong>>항목 둘</li> + <li>항목 <em>셋</em></li> +</ul></pre> + +<p>CSS 에서 마침표 문자로 시작하는 선택자를 작성하여 <code>special</code> class 를 대상으로 할 수 있습니다. CSS 파일에 다음을 추가하십시오:</p> + +<pre class="brush: css">.special { + color: orange; + font-weight: bold; +}</pre> + +<p>저장하고 새로 고침하여 결과를 확인하십시오.</p> + +<p>이 목록 항목과 동일한 모양을 원하는 페이지의 모든 요소에 <code>special</code> class 를 적용할 수 있습니다. 예를 들어, 단락의 <code><span></code> 도 주황색과 굵게 표시할 수 있습니다. <code>special</code> <code>class</code> 를 추가한 다음, 페이지를 새로 고침하여 어떻게 되는지 확인하십시오.</p> + +<p>때로는 HTML 요소 선택자 및 class 목록이 포함된 규칙이 표시됩니다:</p> + +<pre class="brush: css">li.special { + color: orange; + font-weight: bold; +}</pre> + +<p>이 구문은 "spacial class 를 가진 모든 <code>li</code> 요소를 대상으로 함" 을 의미합니다. 이 작업을 수행하면, 단순히 class 를 추가하기만 하면 더 이상 class 를 <code><span></code> 또는 다른 요소에 적용할 수 없습니다. 해당 요소를 선택자 목록에 추가해야 합니다:</p> + +<pre class="brush: css">li.special, +span.special { + color: orange; + font-weight: bold; +}</pre> + +<p>당신이 상상할 수 있듯이, 일부 class 는 많은 요소에 적용될 수 있으며 새로운 스타일을 취해야 할 때마다 CSS 를 계속 편집하지 않아도 됩니다. 따라서 하나의 요소에 대해 특별한 규칙을 만들고 싶거나 다른 요소에 적용되지 않도록 하려는 경우가 아니라면 요소를 무시하고 class 를 참조하는 것이 가장 좋습니다.</p> + +<h2 id="문서에서의_위치에_따라_스타일_지정하기">문서에서의 위치에 따라 스타일 지정하기</h2> + +<p>문서에서의 위치에 따라 무언가 다르게 보일 때가 있습니다. 여기에 당신을 도울 수 있는 선택자가 많이 있지만, 지금 몇 가지만 살펴 보겠습니다. 이 문서에는 두 개의 <code><em></code> 요소가 있습니다 — 하나는 단락 안에 있고 다른 하나는 목록 항목 안에 있습니다. <code><li></code> 요소 안에 중첩된 <code><em></code> 만 선택하려면 <strong>descendant combinator</strong> 라는 선택자를 사용 할 수 있습니다. 이 선택자는 단순히 두 개의 다른 선택자 사이에 공백의 형태를 취합니다.</p> + +<p>스타일 시트에 다음 규칙을 추가 하십시오.</p> + +<pre class="brush: css">li em { + color: rebeccapurple; +}</pre> + +<p>이 선택자는 <code><li></code> 의 하위 요소인 <code><em></code> 요소를 선택합니다. 따라서 예제 문서에서 세 번째 목록 항목의 <code><em></code> 은 이제 자주색 이지만, 단락 안의 항목은 변경되지 않았음을 알 수 있습니다.</p> + +<p>HTML 의 동일한 계층 구조 수준에서 제목 바로 다음에 오는 단락의 스타일을 지정해 볼 수 있습니다. 이렇게 하려면 선택자 사이에 <code>+</code> (<strong>adjacent sibling combinator</strong>) 를 배치 하십시오.</p> + +<p>이 규칙을 스타일 시트에도 추가하십시오:</p> + +<pre class="brush: css">h1 + p { + font-size: 200%; +}</pre> + +<p>아래의 라이브 예제에는 위의 두 규칙이 포함됩니다. 단락 내부에 있는 span 을 빨간색으로 만들려면 규칙을 추가하십시오. 첫 번째 단락의 span 이 빨간색 이므로 올바른 span 이 있는지 알 수 있지만, 첫 번째 목록 항목의 span 은 색이 변경되지 않습니다.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/getting-started/started2.html", '100%', 1100)}}</p> + +<div class="blockIndicator note"> +<p><strong>참고</strong>: 보시다시피, CSS 는 요소를 대상으로 하는 여러 가지 방법을 제공합니다. 이 과정의 뒷부분에서 이러한 선택자 및 선택자 관련 기사를 모두 자세히 살펴볼 것입니다.</p> +</div> + +<h2 id="상태에_따른_스타일링">상태에 따른 스타일링</h2> + +<p>이 자습서에서 살펴볼 스타일링의 마지막 유형은 상태에 따라 스타일을 지정할 수 있는 기능입니다. 이에 대한 간단한 예제는 링크 스타일링 입니다. 링크의 스타일을 지정할 때 <code><a href="/en-US/docs/Web/HTML/Element/a"><a></a></code> (앵커) 요소를 대상으로 해야합니다. 방문되지 않았는지, 방문 중인지, 마우스 오버인지, 키보드를 통한 포커스 또는 클릭 (활성화) 여부에 따라 상태가 다릅니다. CSS 를 사용하여 이러한 다양한 상태를 대상으로 할 수 있습니다. 아래 CSS 는 방문하지 않은 링크는 분홍색이고 방문한 링크는 녹색입니다.</p> + +<pre class="brush: css">a:link { + color: pink; +} + +a:visited { + color: green; +}</pre> + +<p>사용자가 링크 위로 이동할 때 링크 모양을 변경할 수 있습니다. 예를 들어, 다음 규칙에서 밑줄을 제거합니다:</p> + +<pre class="brush: css">a:hover { + text-decoration: none; +}</pre> + +<p>아래 라이브 예제에서는 링크의 다양한 상태에 대해 다른 값으로 표시할 수 있습니다. 위의 규칙을 추가했으며, 이제 핑크 색상이 매우 가볍고 읽기 어렵다는 것을 알고 있습니다. 더 나은 색상으로 바꾸지 않겠습니까? 링크를 굵게 표시할 수 있습니까?</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/getting-started/started3.html", '100%', 900)}} </p> + +<p>우리는 hover 링크에서 밑줄을 제거했습니다. 링크의 모든 상태에서 밑줄을 제거할 수 있습니다. 그러나 실제 사이트에서는 링크임을 방문자에게 알리고자 합니다. 밑줄을 제자리에 두면, 단락 내의 일부 텍스트를 클릭할 수 있다는 사실을 사람들이 인식할 수 있는 중요한 단서가 될 수 있습니다. CSS 의 모든 항목과 마찬가지로 변경 사항으로 인해 문서에 대한 접근성을 떨어뜨릴 수 있는 가능성이 있습니다. 적절한 장소에서 발생할 수 있는 잠재적 위험을 강조하는 것이 목표입니다. </p> + +<div class="blockIndicator note"> +<p><strong>참고</strong>: 이러한 교육 과정과 MDN 전반에 걸쳐 <a href="/en-US/docs/Learn/Accessibility">접근성</a> 에 대한 언급이 자주 있을 것입니다. 접근성에 대해 이야기할 때 웹 페이지를 모든 사용자가 이해하고 사용할 수 있어야 한다는 요구 사항을 언급하고 있습니다.</p> + +<p>방문자는 마우스나 trackpad 또는 터치스크린이 있는 스마트폰에 있을 수 있습니다. 또는 문서의 내용을 읽어내는 스크린 리더를 사용하거나 훨씬 큰 텍스트를 사용하거나 키보드만 사용하여 사이트를 탐색해야 할 수도 있습니다.</p> + +<p>일반 HTML 문서는 일반적으로 모든 사용자가 접근할 수 있습니다. 해당 문서의 스타일을 지정하기 시작하면 접근성이 저하되지 않도록 하는 것이 중요합니다.</p> +</div> + +<h2 id="선택자와_결합자를_결합">선택자와 결합자를 결합</h2> + +<p>여러 선택자와 결합자를 함께 결합할 수 있습니다. 예를 들면 다음과 같습니다:</p> + +<pre class="brush: css">/* <article> 내부의 <p> 안에 있는 모든 <span> 을 선택합니다 */ +article p span { ... } + +/* <h1> 바로 뒤에 오는 <ul> 바로 뒤의 모든 <p> 를 선택합니다 */ +h1 + ul + p { ... }</pre> + +<p>여러 유형을 함께 결합 할 수도 있습니다. 코드에 다음을 추가 하십시오:</p> + +<pre class="brush: css">body h1 + p .special { + color: yellow; + background-color: black; + padding: 5px; +}</pre> + +<p>이것은 <code><body></code> 안에 있는 <code><h1></code> 바로 뒤에 오는 <code><p></code> 안에 있는 <code>special</code> class 를 가진 요소를 스타일링 합니다. 아이고 복잡해라!</p> + +<p>우리가 제공한 원본 HTML 에서 스타일이 지정된 유일한 요소는 <code><span class="special"></code> 입니다.</p> + +<p>현재 이것이 복잡해 보인다고 걱정하지 마십시오 — CSS 를 더 많이 작성할수록 곧 요령을 터득하기 시작할 것입니다.</p> + +<h2 id="마무리">마무리</h2> + +<p>이 자습서에서는, CSS 를 사용하여 문서의 스타일을 지정할 수 있는 여러 가지 방법을 살펴 보았습니다. 우리는 나머지 수업을 진행 하면서 이 지식을 개발할 것입니다. 그러나 이제 텍스트 스타일을 지정하고 문서의 요소를 대상으로 하는 다양한 방법을 기반으로 CSS 를 적용하고 MDN 설명서에서 속성과 값을 검색할 수 있을 정도로 이미 알고 있습니다.</p> + +<p>다음 수업에서는 CSS 가 어떻게 구성되어 있는지 살펴 볼 것입니다.</p> + +<p>{{PreviousMenuNext("Learn/CSS/First_steps/What_is_CSS", "Learn/CSS/First_steps/How_CSS_is_structured", "Learn/CSS/First_steps")}}</p> + +<h2 id="이번_강의에서는">이번 강의에서는</h2> + +<ol> + <li><a href="/en-US/docs/Learn/CSS/First_steps/What_is_CSS">CSS 란 무엇인가?</a></li> + <li><a href="/en-US/docs/Learn/CSS/First_steps/Getting_started">CSS 로 시작하기</a></li> + <li><a href="/en-US/docs/Learn/CSS/First_steps/How_CSS_is_structured">CSS 의 구조</a></li> + <li><a href="/en-US/docs/Learn/CSS/First_steps/How_CSS_works">CSS 작동 방식</a></li> + <li><a href="/en-US/docs/Learn/CSS/First_steps/Using_your_new_knowledge">새로운 지식 사용</a></li> +</ol> diff --git a/files/ko/learn/css/first_steps/how_css_is_structured/index.html b/files/ko/learn/css/first_steps/how_css_is_structured/index.html new file mode 100644 index 0000000000..e7a46f1c7c --- /dev/null +++ b/files/ko/learn/css/first_steps/how_css_is_structured/index.html @@ -0,0 +1,504 @@ +--- +title: CSS 의 구조 +slug: Learn/CSS/First_steps/How_CSS_is_structured +translation_of: Learn/CSS/First_steps/How_CSS_is_structured +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/CSS/First_steps/Getting_started", "Learn/CSS/First_steps/How_CSS_works", "Learn/CSS/First_steps")}}</div> + +<p class="summary">CSS 가 무엇인지, 그리고 CSS 의 기본 사용법에 대해 여러분은 알고 있습니다. 이제 언어 자체의 구조를 조금 더 깊이 살펴볼 차례입니다. 우리는 이미 여기에서 논의된 많은 개념들을 만났습니다. 나중에 혼란스러워 하는 개념을 발견하면, 이 개념으로 돌아와서 요약할 수 있습니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">전제조건:</th> + <td>기본적인 컴퓨터 활용 능력, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Installing_basic_software">기본 소프트웨어 설치</a>, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Dealing_with_files">파일 작업</a> 에 대한 기본 지식, HTML 기본 사항 (<a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">HTML 소개</a> 학습) 및 <a href="/en-US/docs/Learn/CSS/Introduction_to_CSS/How_CSS_works">CSS 작동 방식</a> 이해</td> + </tr> + <tr> + <th scope="row">목적:</th> + <td>CSS 의 기본 구문 구조를 자세히 배우기.</td> + </tr> + </tbody> +</table> + +<h2 id="HTML_에_CSS_적용하기">HTML 에 CSS 적용하기</h2> + +<p>가장 먼저 살펴볼 것은 CSS 를 문서에 적용하는 세 가지 방법입니다.</p> + +<h3 id="외부_스타일_시트">외부 스타일 시트</h3> + +<p><a href="/en-US/docs/Learn/CSS/First_steps/Getting_started">CSS 시작하기</a> 에서 외부 스타일 시트를 페이지에 연결했습니다. CSS 를 여러 페이지에 연결할 수 있으므로, CSS 를 문서에 첨부하는 가장 일반적이고 유용한 방법이며, 모두 동일한 스타일 시트로 CSS 스타일을 지정할 수 있습니다. 대부분의 경우 사이트의 다른 페이지는 모두 거의 동일하게 보이기 때문에 기본 모양과 느낌에 동일한 규칙을 사용할 수 있습니다.</p> + +<p>외부 스타일 시트는 CSS 확장자가 <code>.css</code> 인 별도의 파일로 작성되고, HTML <code><link></code> 요소에서 참조하는 경우입니다:</p> + +<pre class="brush: html"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>나의 CSS 실험</title> + <link rel="stylesheet" href="styles.css"> + </head> + <body> + <h1>헬로우 월드!</h1> + <p>이것은 나의 첫 번째 CSS 예제입니다</p> + </body> +</html></pre> + +<p>CSS 파일은 다음과 같습니다:</p> + +<pre class="brush: css">h1 { + color: blue; + background-color: yellow; + border: 1px solid black; +} + +p { + color: red; +}</pre> + +<p>{{htmlelement("link")}} 요소의 <code>href</code> 속성은 여러분의 파일 시스템 파일을 참조해야 합니다.</p> + +<p>위의 예에서, CSS 파일은 HTML 문서와 동일한 폴더에 있지만, 다른 곳에 저장 한다면, 지정된 경로를 다음과 같이 조정할 수 있습니다:</p> + +<pre class="brush: html"><!-- 현재 폴더의 styles 라는 하위 폴더 안에 --> +<link rel="stylesheet" href="styles/style.css"> + +<!-- 현재 폴더의 styles 라는 하위 폴더에 있는 general 이라는 하위 폴더 안에 --> +<link rel="stylesheet" href="styles/general/style.css"> + +<!-- 상위 폴더로 올라간 다음, styles 라는 하위 폴더 내로 이동 --> +<link rel="stylesheet" href="../styles/style.css"></pre> + +<h3 id="내부_스타일_시트">내부 스타일 시트</h3> + +<p>내부 스타일 시트는 외부 CSS 파일이 없는 대신, HTML {{htmlelement("head")}} 안에 포함된 {{htmlelement("style")}} 요소 내부에 CSS 를 배치합니다.</p> + +<p>따라서 HTML 은 다음과 같습니다:</p> + +<pre class="brush: html"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>나의 CSS 실험</title> + <style> + h1 { + color: blue; + background-color: yellow; + border: 1px solid black; + } + + p { + color: red; + } + </style> + </head> + <body> + <h1>헬로우 월드</h1> + <p>이것은 나의 첫 번째 CSS 예제입니다</p> + </body> +</html></pre> + +<p>이는 일부 상황 (CSS 파일을 직접 수정할 수 없는 콘텐츠 관리 시스템을 사용하는 경우도 있지만) 에서 유용할 수 있지만, CSS 가 필요한 외부 스타일 시트 만큼 효율적이지 않습니다 — 웹 사이트에서, CSS 가 모든 페이지에서 반복되고 변경이 필요한 경우 여러 위치에서 업데이트 됩니다.</p> + +<h3 id="인라인_스타일">인라인 스타일</h3> + +<p>인라인 스타일은 <code>style</code> 속성 내에 포함된 한 요소에만 영향을 주는 CSS 선언입니다:</p> + +<pre class="brush: html"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>나의 CSS 실험</title> + </head> + <body> + <h1 style="color: blue;background-color: yellow;border: 1px solid black;">헬로우 월드!</h1> + <p style="color:red;">이것은 나의 첫 번째 CSS 예제입니다</p> + </body> +</html></pre> + +<p><strong>당신이 정말로 필요하지 않는 한, 이것을 사용하지 마십시오! </strong>유지 관리가 실제로 좋지 않으며 (문서당 동일한 정보를 여러번 업데이트 해야할 수도 있음), 프리젠테이션 CSS 정보와 HTML 구조 정보를 혼합하여 코드를 읽고 이해하기 어렵게 만듭니다. 다른 유형의 코드를 분리하여 유지하면 코드 작업을 하는 모든 사람이 훨씬 쉽게 작업할 수 있습니다.</p> + +<p>인라인 스타일이 더 일반적이거나 권장되는 곳이 몇 군데 있습니다. 작업 환경이 실제로 제한적인 경우 (CMS 로 HTML 본문만 편집할 수 있음), 이를 사용하는 것이 좋습니다. 또한 가능한 많은 전자 메일 클라이언트와 호환되도록 HTML 전자 메일에 많이 사용된 것을 볼 수 있습니다.</p> + +<h2 id="이_기사에서_CSS_로_실습">이 기사에서 CSS 로 실습</h2> + +<p>이 기사에는 많은 CSS 가 있습니다. 이렇게 하려면, 컴퓨터에 새 디렉토리/폴더 를 작성하고 그 안에 다음 두 파일의 복사본을 작성하는 것이 좋습니다:</p> + +<p><strong>index.html:</strong></p> + +<pre class="brush: html"><!DOCTYPE html> +<html lang="ko"> + <head> + <meta charset="utf-8"> + <title>나의 CSS 실험</title> + <link rel="stylesheet" href="styles.css"> + </head> + <body> + + <p>여기에 테스트용 HTML 을 작성하십시오</p> + + </body> +</html></pre> + +<p><strong>styles.css:</strong></p> + +<pre class="brush: css">/* 여기에 테스트용 CSS 를 작성하십시오 */ + +p { + color: red; +}</pre> + +<p>그런 다음, 실험하려는 CSS 를 발견하면, HTML <code><body></code> 콘텐츠를 스타일을 지정할 HTML 로 바꾸고 CSS 를 추가하여 CSS 파일 내에서 스타일을 지정하십시오.</p> + +<p>파일을 쉽게 만들 수 있는 시스템을 사용하지 않는 경우, 아래의 대화식 편집기를 사용하여 실험해 보십시오.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/getting-started/experiment-sandbox.html", '100%', 800)}} </p> + +<p>읽고, 재미있게 보내십시오!</p> + +<h2 id="선택자_Selectors">선택자 (Selectors)</h2> + +<p>선택자를 만나지 않고 CSS 에 대해 이야기할 수 없으며, <a href="/en-US/docs/Learn/CSS/First_steps/Getting_started">CSS 시작하기</a> 자습서에서 이미 여러 가지 유형을 발견했습니다. 선택자는 스타일을 적용하기 위해 HTML 문서에서 무언가를 대상으로 하는 방법입니다. 스타일이 적용되지 않으면 선택자가 일치해야 하는 것과 동일하지 않을 수 있습니다.</p> + +<p>각 CSS 규칙은 선택자 또는 선택자 목록으로 시작하여 규칙을 적용해야 하는 요소 또는 요소 규칙을 브라우저에게 알려줍니다. 다음은 모두 유효한 선택자 또는 선택자 목록의 예입니다.</p> + +<pre class="brush: css">h1 +a:link +.manythings +#onething +* +.box p +.box p:first-child +h1, h2, .intro</pre> + +<p><strong>위의 선택자를 사용하는 CSS 규칙과 스타일을 적용할 일부 HTML 을 만들어 보십시오. 위 구문 중 일부가 무엇을 의미하는지 모르는 경우, MDN 에서 검색해 보십시오!</strong></p> + +<div class="blockIndicator note"> +<p><strong>참고</strong>: 다음 과목의 <a href="/en-US/docs/Learn/CSS/Building_blocks/Selectors">CSS 선택자</a> 자습서에서, 선택자에 대해 자세히 학습합니다.</p> +</div> + +<h3 id="우선_순위_Specificity">우선 순위 (Specificity)</h3> + +<p>두 선택자가 동일한 HTML 요소를 선택할 수 있는 경우가 종종 있습니다. 단락을 파란색으로 설정하는 <code>p</code> 선택자 및 선택한 요소를 빨간색으로 설정하는 class 가 있는 아래 스타일 시트를 고려하십시오.</p> + +<pre class="brush: css">.special { + color: red; +} + +p { + color: blue; +}</pre> + +<p>HTML 문서에 <code>special</code> class 가 있는 단락이 있다고 가정해 봅시다. 두 규칙이 모두 적용될 수 있으므로 어느 쪽이 이길까요? 우리의 문단은 어떤 색이 될 것이라고 생각합니까?</p> + +<pre class="brush: html"><p class="special">나는 무슨 색입니까?</p></pre> + +<p>CSS 언어에는 충돌시 어떤 규칙이 이기는지 제어하는 규칙이 있습니다 — 이러한 규칙을 <strong>계단식(cascade)</strong> 및 <strong>우선 순위(specificity)</strong> 라고 합니다. 아래 코드 블록에서 <code>p</code> 선택자에 대해 두 가지 규칙을 정의했지만, 단락이 파란색으로 표시됩니다. 파란색으로 설정한 선언은 스타일 시트에서 나중에 나타나고 이후 스타일은 이전 스타일을 재정의 하기 때문입니다. 이것은 실제의 계단식 (cascade) 입니다.</p> + +<pre class="brush: css">p { + color: red; +} + +p { + color: blue; +}</pre> + +<p>그러나, class 선택자 및 요소 선택자가 있는 이전 블록의 경우, class 가 이기고 단락이 빨간색으로 표시됩니다 — class 는 요소 선택자 보다 더 구체적이거나 더 우선 순위가 높은 것으로 설명되므로 이깁니다.</p> + +<p><strong>위 실험을 직접해 보십시오 — 실험에 HTML 을 추가한 다음, 스타일 시트에 두 개의 <code>p { ... }</code> 규칙을 추가하십시오. 그런 다음 첫 번째 <code>p</code> 선택자를 <code>.special</code> 로 변경하여 스타일이 어떻게 되는지 확인하십시오.</strong></p> + +<p>우선 순위 규칙과 계단식은 처음에는 약간 복잡해 보일 수 있으며 CSS 지식을 더 많이 쌓으면 이해하기 쉽습니다. 다음 과목에서 다룰 <a href="/en-US/docs/Learn/CSS/Building_blocks/Cascade_and_inheritance">계단식 및 상속</a> 기사에서, 우선 순위를 계산하는 방법을 포함하여 자세히 설명하겠습니다. 현재로서는 이것이 존재하며, 스타일 시트의 다른 요소가 더 높은 우선 순위를 가지기 때문에 CSS 가 예상한 대로 적용되지 않을 수도 있음을 기억하십시오. 하나 이상의 규칙이 요소에 적용될 수 있음을 식별하는 것이 이러한 문제를 해결하는 첫 번째 단계입니다.</p> + +<h2 id="속성_및_값">속성 및 값</h2> + +<p>가장 기본적인 수준에서, CSS 는 두 가지 요소로 구성됩니다:</p> + +<ul> + <li><strong>속성 (Properties)</strong>: 변경할 스타일 기능 (예: <code><a href="/en-US/docs/Web/CSS/font-size">font-size</a></code>, <code><a href="/en-US/docs/Web/CSS/width">width</a></code>, <code><a href="/en-US/docs/Web/CSS/background-color">background-color</a></code>) 을 나타내는 식별자입니다.</li> + <li><strong>값 (Values)</strong>: 지정된 각 속성에는 값이 지정되어 있으며, 이는 해당 스타일 기능을 변경하는 방법 (예: 글꼴, 너비 또는 배경색을 변경하려는 항목) 을 나타냅니다.</li> +</ul> + +<p>아래 이미지는 단일 속성과 값을 강조 표시합니다. 속성 이름은 <code>color</code> 이고 값은 <code>blue</code> 입니다.</p> + +<p><img alt="A declaration highlighted in the CSS" src="https://mdn.mozillademos.org/files/16498/declaration.png" style="border: 1px solid #cccccc; display: block; height: 218px; margin: 0 auto; width: 471px;"></p> + +<p>값 과 쌍을 이루는 속성을 <em>CSS <strong>선언 (declaration)</strong></em> 이라고 합니다. CSS 선언은 <em>CSS <strong>선언 블록</strong></em> 안에 있습니다. 다음 이미지는 선언 블록이 강조 표시된 CSS 를 보여줍니다.</p> + +<p><img alt="A highlighted declaration block" src="https://mdn.mozillademos.org/files/16499/declaration-block.png" style="border: 1px solid #cccccc; display: block; height: 218px; margin: 0 auto; width: 471px;"></p> + +<p>마지막으로, CSS 선언 블록은 <em>선택자 </em>와 쌍을 이루어 <em>CSS Rulesets</em> (또는 <em>CSS <strong>규칙</strong> </em>) 를 생성합니다. 이미지에는 <code>h1</code> 선택자 및 <code>p</code> 선택자의 두 가지 규칙이 있습니다. <code>h1</code> 의 규칙이 강조 표시됩니다.</p> + +<p><img alt="The rule for h1 highlighted" src="https://mdn.mozillademos.org/files/16500/rules.png" style="border: 1px solid #cccccc; display: block; height: 218px; margin: 0 auto; width: 471px;"></p> + +<p>CSS 속성을 특정 값으로 설정하는 것은 CSS 언어의 핵심 기능입니다. CSS 엔진은 페이지의 모든 단일 요소에 적용할 선언을 계산하여 적절하게 배치하고 스타일을 지정합니다. 기억해야 할 것은 CSS 에서 속성과 값이 모두 대소문자를 구분한다는 것입니다. 각 쌍의 속성 과 값은 콜론 (<code>:</code>) 으로 구분됩니다.</p> + +<p><strong>다음 속성의 다른 값을 찾아 다른 HTML 요소에 적용하는 CSS 규칙을 작성하십시오: </strong></p> + +<ul> + <li><strong>{{cssxref("font-size")}}</strong></li> + <li><strong>{{cssxref("width")}}</strong></li> + <li><strong>{{cssxref("background-color")}}</strong></li> + <li><strong>{{cssxref("color")}}</strong></li> + <li><strong>{{cssxref("border")}}</strong></li> +</ul> + +<div class="warning"> +<p><strong>중요</strong>: 속성을 알 수 없거나 지정된 속성에 대해 값이 유효하지 않은 경우, 선언이 유효하지 않은 것으로 간주되어 브라우저의 CSS 엔진에서 완전히 무시됩니다.</p> +</div> + +<div class="warning"> +<p><strong>중요</strong>: CSS (및 기타 웹 표준) 에서, 언어의 불확실성이 발생하는 경우, 미국 맞춤법이 표준으로 합의 되었습니다. 예를 들어, <code>color</code> 는 <em>항상</em> <code>color</code> 여야 합니다. <code>colour</code> 는 작동하지 않습니다.</p> +</div> + +<h3 id="함수_function">함수 (function)</h3> + +<p>대부분의 값은 비교적 간단한 키워드 또는 숫자 값이지만, 함수의 형태를 취하는 몇 가지 가능한 값이 있습니다. <code>calc()</code> 함수를 예로 들 수 있습니다. 이 함수를 사용하면 CSS 내에서 간단한 계산을 수행할 수 있습니다. 예를 들면 다음과 같습니다:</p> + +<div id="calc_example"> +<pre class="brush: html"><div class="outer"><div class="box">The inner box is 90% - 30px.</div></div></pre> + +<pre class="brush: css">.outer { + border: 5px solid black; +} + +.box { + padding: 10px; + width: calc(90% - 30px); + background-color: rebeccapurple; + color: white; +}</pre> +</div> + +<p>이것은 다음과 같이 렌더링 됩니다:</p> + +<p>{{EmbedLiveSample('calc_example', '100%', 200)}}</p> + +<p>함수는 함수 이름과 해당 함수에 허용된 값이 배치되는 괄호들로 구성됩니다. 위의 <code>calc()</code> 예제의 경우, 이 박스의 너비는 블록 너비의 90% 에서 30 px 을 뺀 값을 요구합니다. 이것은 90%가 무엇인지 알지 못하기 때문에 미리 계산하고 CSS 에 값을 입력할 수 있는 것이 아닙니다. 모든 값과 마찬가지로 MDN 의 관련 페이지에 사용법 예제가 있으므로 기능의 작동 방식을 확인할 수 있습니다.</p> + +<p>또 다른 예는 <code>rotate()</code> 와 같은 {{cssxref("transform")}} 에 대한 다양한 값입니다.</p> + +<div id="transform_example"> +<pre class="brush: html"><div class="box"></div></pre> + +<pre class="brush: css">.box { + margin: 30px; + width: 100px; + height: 100px; + background-color: rebeccapurple; + transform: rotate(0.8turn) +}</pre> +</div> + +<p>위 코드의 결과는 다음과 같습니다:</p> + +<p>{{EmbedLiveSample('transform_example', '100%', 200)}}</p> + +<p><strong>다음 속성의 다른 값을 찾아 다른 HTML 요소에 적용하는 CSS 규칙을 작성 하십시오: </strong></p> + +<ul> + <li><strong>{{cssxref("transform")}}</strong></li> + <li><strong>{{cssxref("background-image")}}, in particular gradient values</strong></li> + <li><strong>{{cssxref("color")}}, in particular rgb/rgba/hsl/hsla values</strong></li> +</ul> + +<h2 id="rules">@rules</h2> + +<p>아직, 우리는 <code><a href="/en-US/docs/Web/CSS/At-rule">@rules</a></code> ("at-rules" 로 발음) 가 발생하지 않았습니다. 이것들은 CSS 에 행동 방법에 대한 지침을 제공하는 특수 규칙입니다. 일부 <code>@rules</code> 는 규칙 이름과 값으로 단순합니다. 예를 들어, 추가 스타일 시트를 기본 CSS 스타일 시트로 가져오려면 <code>@import</code> 를 사용할 수 있습니다:</p> + +<pre class="brush: css">@import 'styles2.css';</pre> + +<p>접하게 될 가장 일반적인 <code>@rules</code> 중 하나는 <code>@media</code> 입니다. 이는 특정 조건이 참일 때만 (예: 화면 해상도가 일정 폭 이상이거나 화면이 일정 폭 보다 넓을 때) CSS 를 적용할 수 있는 <a href="/en-US/docs/Web/CSS/Media_Queries">미디어 쿼리</a> 를 사용할 수 있습니다.</p> + +<p>아래 CSS 에는, <code><body></code> 요소에 분홍색 배경색을 주는 스타일 시트가 있습니다. 그러나, <code>@media</code> 를 사용하여 30em 보다 넓은 viewport 가 있는 브라우저에만 적용되는 스타일 시트 섹션을 만듭니다. 브라우저가 30em 보다 넓은 경우 배경색이 파란색이 됩니다.</p> + +<pre class="brush: css">body { + background-color: pink; +} + +@media (min-width: 30em) { + body { + background-color: blue; + } +}</pre> + +<p>이 자습서를 통해 다른 <code>@rules</code> 를 접하게 될 것입니다.</p> + +<p><strong>viewport 너비에 따라 스타일을 변경하는 미디어 쿼리를 CSS 에 추가할 수 있는지 확인 하십시오. 결과를 보려면 브라우저 창의 너비를 변경하십시오.</strong></p> + +<h2 id="속기_shorthands">속기 (shorthands)</h2> + +<p>{{cssxref("font")}}, {{cssxref("background")}}, {{cssxref("padding")}}, {{cssxref("border")}} 및 {{cssxref("margin")}} 등의 일부 속성은 <strong>속기 속성</strong> 이라고 불립니다 — 이는 여러 줄의 속성 값을 한 줄로 설정하여 시간을 절약하고 작업에서 코드를 깔끔하게 만들 수 있기 때문입니다.</p> + +<p>예를 들어, 다음 행은:</p> + +<pre class="brush: css">/* 패딩 및 마진과 같은 4-값 속기에서는 위, 오른쪽, 아래, 왼쪽 (위에서 부터 시계방향) 순서로 값이 적용됩니다. + 위, 아래에 패딩 / 마진을 설정하고 왼쪽 / 오른쪽에 패딩 / 마진을 설정하는 다른 shorthand 유형 (예: 2-값 shorthands)도 있습니다. */ +padding: 10px 15px 15px 5px;</pre> + +<p>이것들은 모두 이것과 똑같습니까?</p> + +<pre class="brush: css">padding-top: 10px; +padding-right: 15px; +padding-bottom: 15px; +padding-left: 5px;</pre> + +<p>다음 행은:</p> + +<pre class="brush: css">background: red url(bg-graphic.png) 10px 10px repeat-x fixed;</pre> + +<p>이 모든 것들과 같은 작업을 수행합니다:</p> + +<pre class="brush: css">background-color: red; +background-image: url(bg-graphic.png); +background-position: 10px 10px; +background-repeat: repeat-x; +background-attachment: fixed;</pre> + +<p>우리는 지금 이것들을 철저하게 가르치려고 하지 않을 것입니다 — 당신은 이 과정 후반에 많은 예제들을 보게 될 것입니다. 그리고 더 많은 정보를 얻기 위해, <a href="/en-US/docs/Web/CSS/Reference">CSS 참조</a> 에서 속기 속성 이름을 찾아 보는 것이 좋습니다.</p> + +<p><strong>위의 선언을 CSS 에 추가하여 HTML 스타일에 어떤 영향을 미치는지 확인 하십시오. 다른 값으로 실험해 보십시오.</strong></p> + +<div class="blockIndicator warning"> +<p><strong>경고</strong>: 속기는 종종 값을 놓칠 수 있지만, 포함하지 않은 값을 초기 값으로 재설정합니다. 이를 통해 합리적인 값 세트가 사용됩니다. 그러나, 속기에서 전달한 값만 변경하려는 경우에는 혼동 될 수 있습니다.</p> +</div> + +<h2 id="주석_comments">주석 (comments)</h2> + +<p>HTML 과 마찬가지로 CSS 에 주석을 달아 몇 달 후에 코드가 다시 작동 할 때, 코드 작동 방식을 이해하고 코드를 사용하는 다른 사람들이 이해하도록 도와주는 것이 좋습니다.</p> + +<p>CSS 의 주석은 <code>/*</code> 로 시작하고 <code>*/</code> 로 끝납니다. 아래 코드 블록에서 주석을 사용하여 다른 고유 코드 섹션의 시작을 표시했습니다. 코드가 커질수록 코드를 탐색하는 데 유용합니다 — 코드 편집기에서 주석을 검색할 수 있습니다.</p> + +<pre class="brush: css">/* 기본 요소 스타일링 처리 */ +/* -------------------------------------------------------------------------------------------- */ +body { + font: 1em/150% Helvetica, Arial, sans-serif; + padding: 1em; + margin: 0 auto; + max-width: 33em; +} + +@media (min-width: 70em) { + /* 전역 글꼴 크기의 특수한 경우를 봅시다. +큰 화면이나 창에서 가독성을 높이기 위해, +글꼴 크기를 늘립니다. */ + body { + font-size: 130%; + } +} + +h1 {font-size: 1.5em;} + +/* DOM 에 중첩된 특정 요소 처리 */ +/* -------------------------------------------------------------------------------------------- */ +div p, #id:first-line { + background-color: red; + border-radius: 3px; +} + +div p { + margin: 0; + padding: 1em; +} + +div p + p { + padding-top: 0; +}</pre> + +<p>주석은 테스트 목적으로 코드의 특정 부분을 일시적으로 <em><strong>주석 처리</strong> </em>하는 경우에도 유용합니다. 예를 들어, 코드의 어느 부분에서 오류가 발생했는지 확인하려는 경우. 다음 예제에서는 <code>.special</code> 선택자에 대한 규칙을 주석 처리 했습니다.</p> + +<pre class="brush: css">/*.special { + color: red; +}*/ + +p { + color: blue; +}</pre> + +<p><strong>CSS 에 주석을 추가하여 사용에 익숙해 지십시오.</strong></p> + +<h2 id="공백_whitespace">공백 (whitespace)</h2> + +<p>공백은 실제 공간, 탭 및 줄 바꿈을 의미합니다. HTML 과 같은 방식으로 브라우저는 CSS 내부의 많은 공백을 무시하는 경향이 있습니다. 가독성을 돕기위해 많은 공백이 있습니다.</p> + +<p>아래 첫 번째 예에서는 각 선언 (및 규칙 시작/종료) 이 각 라인에 있습니다 — 이는 CSS 를 유지 관리하고 이해하기 쉽기 때문에 CSS 를 작성하는 좋은 방법입니다:</p> + +<pre class="brush: css">body { + font: 1em/150% Helvetica, Arial, sans-serif; + padding: 1em; + margin: 0 auto; + max-width: 33em; +} + +@media (min-width: 70em) { + body { + font-size: 130%; + } +} + +h1 { + font-size: 1.5em; +} + +div p, +#id:first-line { + background-color: red; + border-radius: 3px; +} + +div p { + margin: 0; + padding: 1em; +} + +div p + p { + padding-top: 0; +}You could write exactly the same CSS like so, with most of the whitespace removed — this is functionally identical to the first example, but I'm sure you'll agree that it is somewhat harder to read:</pre> + +<pre class="brush: css">body {font: 1em/150% Helvetica, Arial, sans-serif; padding: 1em; margin: 0 auto; max-width: 33em;} +@media (min-width: 70em) { body {font-size: 130%;} } + +h1 {font-size: 1.5em;} + +div p, #id:first-line {background-color: red; border-radius: 3px;} +div p {margin: 0; padding: 1em;} +div p + p {padding-top: 0;} +</pre> + +<p>대부분의 공백을 제거한 상태에서 정확히 동일한 CSS 를 작성할 수 있습니다. 이것은 첫 번째 예제와 기능적으로 동일하지만 읽기가 다소 어렵다는 데 동의합니다.</p> + +<div class="blockIndicator warning"> +<p>CSS 에서 속성 과 값 사이의 공백은 주의해야 합니다.</p> +</div> + +<p>예를 들어, 다음 선언은 유효한 CSS 입니다:</p> + +<pre class="brush: css">margin: 0 auto; +padding-left: 10px;</pre> + +<p>그러나 다음은 유효하지 않습니다:</p> + +<pre class="brush: css">margin: 0auto; +padding- left: 10px;</pre> + +<div class="blockIndicator warning"> +<p><code>0auto</code> 는 <code>margin</code> 속성 (<code>0</code> 과 <code>auto</code> 는 두 개의 개별 값임)에 유효한 값으로 인식되지 않으며, 브라우저는 <code>padding-</code> 을 유효한 속성으로 인식하지 않습니다. 따라서 항상 공백으로 구분된 값을 구분해야 하지만 속성 이름과 속성 값을 하나의 끊김 없는 문자열로 유지해야 합니다.</p> +</div> + +<p><strong>CSS 내부에서 공백을 사용하여 문제를 해결하고 그렇지 않은 것을 확인하십시오.</strong></p> + +<h2 id="다음은_뭐죠">다음은 뭐죠?</h2> + +<p>브라우저가 HTML 과 CSS 를 가져와서 웹 페이지로 전환하는 방법에 대해 약간 이해하는 것이 유용합니다. 따라서 다음 기사 — <a href="/en-US/docs/Learn/CSS/First_steps/How_CSS_works">CSS 작동 방식</a> — 에서 해당 작업을 살펴 보겠습니다.</p> + +<p>{{PreviousMenuNext("Learn/CSS/First_steps/Getting_started", "Learn/CSS/First_steps/How_CSS_works", "Learn/CSS/First_steps")}}</p> + +<h2 id="이번_강의에서는">이번 강의에서는</h2> + +<ol> + <li><a href="/en-US/docs/Learn/CSS/First_steps/What_is_CSS">CSS 란 무엇인가?</a></li> + <li><a href="/en-US/docs/Learn/CSS/First_steps/Getting_started">CSS 시작하기</a></li> + <li><a href="/en-US/docs/Learn/CSS/First_steps/How_CSS_is_structured">CSS 구조</a></li> + <li><a href="/en-US/docs/Learn/CSS/First_steps/How_CSS_works">CSS 작동 방식</a></li> + <li><a href="/en-US/docs/Learn/CSS/First_steps/Using_your_new_knowledge">새로운 지식 사용</a></li> +</ol> diff --git a/files/ko/learn/css/first_steps/how_css_works/index.html b/files/ko/learn/css/first_steps/how_css_works/index.html new file mode 100644 index 0000000000..00104dfc85 --- /dev/null +++ b/files/ko/learn/css/first_steps/how_css_works/index.html @@ -0,0 +1,156 @@ +--- +title: CSS 작동 방식 +slug: Learn/CSS/First_steps/How_CSS_works +translation_of: Learn/CSS/First_steps/How_CSS_works +--- +<p>{{LearnSidebar}}<br> + {{PreviousMenuNext("Learn/CSS/First_steps/How_CSS_is_structured", "Learn/CSS/First_steps/Using_your_new_knowledge", "Learn/CSS/First_steps")}}</p> + +<p class="summary">CSS 기본 사항, CSS 의 목적 및 간단한 스타일 시트 작성 방법을 배웠습니다. 이 강의에서는 브라우저가 CSS 와 HTML 을 가져와서 웹 페이지로 만드는 방법을 살펴 봅니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">전제조건:</th> + <td>기본적인 컴퓨터 활용능력, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Installing_basic_software">기본 소프트웨어 설치</a>, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Dealing_with_files">파일 작업</a>의 기본 지식 및 HTML 기본 사항 (<a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">HTML 소개</a> 학습.)</td> + </tr> + <tr> + <th scope="row">목적:</th> + <td>브라우저에서 CSS 와 HTML 을 구문 분석하는 방법의 기본 사항과 브라우저에서 CSS 를 이해하지 못할 경우 어떻게 되는지 이해하기.</td> + </tr> + </tbody> +</table> + +<h2 id="CSS_는_실제로_어떻게_작동합니까">CSS 는 실제로 어떻게 작동합니까?</h2> + +<p>브라우저가 문서를 표시할 때, 문서의 콘텐츠와 해당 스타일 정보를 결합해야 합니다. 아래 나열된 여러 단계로 문서를 처리합니다. 이것은 브라우저가 웹 페이지를 로드할 때 발생하는 작업의 매우 단순화된 버전이며, 다른 브라우저가 다른 방식으로 작업을 처리한다는 점을 명심하십시오. 그러나 이것은 대략 일어나는 일입니다.</p> + +<ol> + <li>브라우저는 HTML (예: 네트워크에서 HTML 을 수신) 을 로드합니다.</li> + <li>{{Glossary("HTML")}} 을 {{Glossary("DOM")}} (<em>Document Object Model</em>) 로 변환합니다. DOM 은 컴퓨터 메모리의 문서를 나타냅니다. DOM 은 다음 섹션에서 좀 더 자세히 설명됩니다.</li> + <li>그런 다음 브라우저는 포함된 이미지 및 비디오와 같은 HTML 문서에 연결된 대부분의 리소스와 연결된 CSS 를 가져옵니다! JavaScript 는 작업에서 나중에 처리되므로 더 간단하게 하기위해 여기에서는 다루지 않습니다.</li> + <li>브라우저는 가져온 CSS 를 구문 분석하고 선택자 유형별로 다른 규칙을 다른 "buckets" 으로 정렬합니다. 예: 요소, class, ID 등 찾은 선택자를 기반으로 DOM 의 어느 노드에 어떤 규칙을 적용해야 하는지 결정하고, 필요에 따라 스타일을 첨부합니다 (이 중간 단계를 render tree 라고 합니다).</li> + <li>render tree 는 규칙이 적용된 후에 표시되어야 하는 구조로 배치됩니다.</li> + <li>페이지의 시각적 표시가 화면에 표시됩니다 (이 단계를 painting 이라고 함).</li> +</ol> + +<p>다음 그림은 작업의 간단한 보기를 제공합니다.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/11781/rendering.svg" style="height: auto; max-width: 635px; width: 100%;"></p> + +<h2 id="DOM_정보">DOM 정보</h2> + +<p>DOM 은 트리와 같은 구조를 가지고 있습니다. 마크 업 언어의 각 요소, 속성 및 텍스트는 트리 구조에서 {{Glossary("Node/DOM","DOM node")}} 가 됩니다. 노드는 다른 DOM 노드와의 관계에 의해 정의됩니다. 일부 요소는 자식 노드의 부모이고 자식 노드에는 형제가 있습니다.</p> + +<p>DOM 은 CSS 와 문서의 내용이 만나는 곳이기 때문에 DOM 을 이해하면 CSS 를 설계, 디버그 및 유지 관리하는 데 도움이 됩니다. 브라우저 DevTools 로 작업을 시작하면, 적용할 규칙을 보기 위해 항목을 선택할 때 DOM 을 탐색하게 됩니다.</p> + +<h2 id="실제_DOM_표현">실제 DOM 표현</h2> + +<p>길고 지루한 설명이 아니라 실제 HTML 이 DOM 으로 변환되는 방법을 보여주는 예제를 살펴 보겠습니다.</p> + +<p>다음 HTML 코드를 사용하십시오:</p> + +<pre class="brush: html"><p> + Let's use: + <span>Cascading</span> + <span>Style</span> + <span>Sheets</span> +</p> +</pre> + +<p>DOM 에서, <code><p></code> 요소에 해당하는 노드는 부모입니다. 자식은 텍스트 노드이고 <code><span></code> 요소에 해당하는 세 개의 노드입니다. <code>SPAN</code> 노드는 부모이며, 텍스트 노드는 자식입니다:</p> + +<pre>P +├─ "Let's use:" +├─ SPAN +| └─ "Cascading" +├─ SPAN +| └─ "Style" +└─ SPAN + └─ "Sheets" +</pre> + +<p>브라우저가 이전 HTML 을 해석하는 방법입니다 — 위의 DOM 트리를 렌더링 한 다음 브라우저에서 다음과 같이 출력합니다:</p> + +<p>{{EmbedLiveSample('A_real_DOM_representation', '100%', 55)}}</p> + +<div class="hidden"> +<pre class="brush: css">p {margin:0;}</pre> +</div> + +<h2 id="DOM_에_CSS_적용하기">DOM 에 CSS 적용하기</h2> + +<p>CSS 를 문서에 추가하여 스타일을 지정했다고 가정해 봅시다. 다시 한 번, HTML 은 다음과 같습니다:</p> + +<pre class="brush: html"><p> + Let's use: + <span>Cascading</span> + <span>Style</span> + <span>Sheets</span> +</p></pre> + +<p>다음 CSS 를 적용한다고 가정해 봅시다:</p> + +<pre class="brush: css">span { + border: 1px solid black; + background-color: lime; +}</pre> + +<p>브라우저는 HTML 을 구문 분석하고 그로부터 DOM 을 작성한 다음, CSS 를 구문 분석합니다. CSS 에서 사용할 수 있는 유일한 규칙에는 <code>span</code> 선택자가 있으므로, 브라우저는 CSS 를 매우 빠르게 정렬할 수 있습니다! 이 규칙을 세 개의 <code><span></code> 각각에 적용한 다음 최종 시각적 표현을 화면에 표시합니다.</p> + +<p>업데이트 된 출력은 다음과 같습니다:</p> + +<p>{{EmbedLiveSample('Applying_CSS_to_the_DOM', '100%', 55)}}</p> + +<p>다음 과목의 <a href="/en-US/docs/Learn/CSS/Building_blocks/Debugging_CSS">CSS 디버깅</a> 기사에서 브라우저 DevTools 를 사용하여, CSS 문제를 디버깅하고 브라우저가 CSS 를 해석하는 방법에 대해 자세히 알아 봅니다.</p> + +<h2 id="브라우저에서_인식하지_못하는_CSS_를_발견하면_어떻게_됩니까">브라우저에서 인식하지 못하는 CSS 를 발견하면 어떻게 됩니까?</h2> + +<p><a href="/en-US/docs/Learn/CSS/First_steps/What_is_CSS#Browser_support">이전 수업</a> 에서 브라우저가 모두 동시에 새로운 CSS 를 구현하는 것은 아니라고 언급했습니다. 또한 많은 사람들이 최신 버전의 브라우저를 사용하지 않습니다. CSS 가 항상 개발되고 있으므로 브라우저가 인식할 수 있는 것보다 앞서 있기 때문에 브라우저가 CSS 선택자 또는 인식하지 못하는 선언을 발견하면 어떻게 될지 궁금할 수 있습니다.</p> + +<p>대답은 아무것도 하지 않으며, CSS 의 다음 단계로 넘어갑니다!</p> + +<p>브라우저가 규칙을 구문 분석하고 이해하지 못하는 속성 이나 값을 발견하면, 이를 무시하고 다음 선언으로 넘어갑니다. 오류가 발생하여 속성 또는 값의 철자가 틀렸거나 속성 또는 값이 너무 새롭고 브라우저가 아직 이를 지원하지 않는 경우, 이 작업을 수행합니다.</p> + +<p>마찬가지로, 브라우저가 이해하지 못하는 선택자를 만나면, 전체 규칙을 무시하고 다음 규칙으로 넘어갑니다.</p> + +<p>아래 예에서 나는 영국 영어 철자를 색상에 사용했는데, 그 속성은 인식되지 않기 때문에 유효하지 않습니다. 그래서 내 단락은 파란색으로 표시되지 않았습니다. 그러나 다른 모든 CSS 가 적용 되었습니다. 유효하지 않은 라인만 무시됩니다.</p> + +<div id="Skipping_example"> +<pre class="brush: html"><p> 나는 이 텍스트를 크고 굵은 파란색으로 표시하고 싶습니다.</p></pre> + +<pre class="brush: css">p { + font-weight: bold; + colour: blue; /* color 속성의 잘못된 철자 */ + font-size: 200%; +}</pre> +</div> + +<p>{{EmbedLiveSample('Skipping_example', '100%', 200)}}</p> + +<p>이 동작은 매우 유용합니다. 이는 새로운 CSS 를 향상된 기능으로 사용할 수 있음을 의미하며, 새 기능을 이해하지 못할 경우 오류가 발생하지 않습니다 — 브라우저는 새로운 기능을 얻거나 얻지 못합니다. cascade 작동 방식 및 브라우저가 스타일이 동일한 마지막 CSS 를 사용한다는 사실과 동일한 특성을 가진 두 규칙이 있을 경우, 새 CSS 를 지원하지 않는 브라우저에 대한 대안을 제공할 수도 있습니다.</p> + +<p>이것은 새롭고 모든 곳에서 지원되지 않는 값을 사용하려는 경우 특히 효과적입니다. 예를 들어, 구형 브라우저는 <code>calc()</code> 를 값으로 지원하지 않습니다. 박스에 대해 대체 너비를 픽셀 단위로 지정한 다음, <code>calc()</code> 값을 <code>100% - 50px</code> 로 너비를 지정하십시오. 오래된 브라우저는 픽셀 버전을 사용하지만, 이해하지 못하는 <code>calc()</code> 에 대한 라인은 무시합니다. 새로운 브라우저는 픽셀을 사용하여 라인을 해석하지만, 나중에 cascade 에서 나타날 때 <code>calc()</code> 를 사용하여 라인을 재정의 합니다.</p> + +<pre class="brush: css">.box { + width: 500px; + width: calc(100% - 50px); +}</pre> + +<p>우리는 이후 수업에서 다양한 브라우저를 지원하는 더 많은 방법을 다룰 것입니다.</p> + +<h2 id="마지막으로">마지막으로</h2> + +<p>이 강의를 거의 끝냈습니다; 할 일이 하나 더 있습니다. 다음 기사에서는 <a href="/en-US/docs/Learn/CSS/First_steps/Using_your_new_knowledge">새로운 지식을 사용</a> 하여 예제의 스타일을 변경하여 작업의 일부 CSS 를 테스트 합니다.</p> + +<p>{{PreviousMenuNext("Learn/CSS/First_steps/How_CSS_is_structured", "Learn/CSS/First_steps/Using_your_new_knowledge", "Learn/CSS/First_steps")}}</p> + +<h2 id="이번_강의에서는">이번 강의에서는</h2> + +<ol> + <li><a href="/en-US/docs/Learn/CSS/First_steps/What_is_CSS">CSS 란 무엇인가?</a></li> + <li><a href="/en-US/docs/Learn/CSS/First_steps/Getting_started">CSS 로 시작하기</a></li> + <li><a href="/en-US/docs/Learn/CSS/First_steps/How_CSS_is_structured">CSS 의 구조</a></li> + <li><a href="/en-US/docs/Learn/CSS/First_steps/How_CSS_works">CSS 작동 방식</a></li> + <li><a href="/en-US/docs/Learn/CSS/First_steps/Using_your_new_knowledge">새로운 지식을 사용</a></li> +</ol> diff --git a/files/ko/learn/css/first_steps/index.html b/files/ko/learn/css/first_steps/index.html new file mode 100644 index 0000000000..e03e748853 --- /dev/null +++ b/files/ko/learn/css/first_steps/index.html @@ -0,0 +1,46 @@ +--- +title: CSS 첫 번째 단계 +slug: Learn/CSS/First_steps +translation_of: Learn/CSS/First_steps +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">CSS (Cascading Style Sheets) 는 콘텐츠의 글꼴, 색상, 크기 및 간격을 변경하거나 여러 열로 분할하거나 애니메이션 및 기타 장식 기능을 추가하는 등의 웹 페이지 스타일 및 레이아웃에 사용됩니다. 이 모듈은 작동 방식, 구문의 모양 및 HTML에 스타일을 추가하기 위해, 이를 사용하는 방법에 대한 기본 사항을 통해 CSS 를 마스터 하는 과정을 부드럽게 시작합니다.</p> + +<h2 id="전제_조건">전제 조건</h2> + +<p>이 모듈을 시작하기 전에, 다음이 있어야 합니다:</p> + +<ol> + <li>컴퓨터를 사용하고 웹을 수동적으로 사용하는 것에 대한 기본적인 친숙성 (예: 콘텐츠를 보는 것) 입니다.</li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web/Installing_basic_software">기본 소프트웨어 설치</a> 에서 자세히 설명한 대로 설정된 기본 작업 환경과 <a href="https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web/Dealing_with_files">파일 다루기</a> 에서 자세히 설명한 대로 파일을 생성하고 관리하는 방법을 이해합니다.</li> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">HTML 소개</a> 에서 설명한 바와 같이 HTML에 대한 기본적인 친숙성입니다.</li> +</ol> + +<div class="note"> +<p><strong>참고</strong>: 자신의 파일을 만들 수 없는 컴퓨터/태블릿/기타 장치에서 작업하는 경우, <a href="http://jsbin.com/">JSBin</a> 또는 <a href="https://glitch.com/">Glitch</a> 와 같은 온라인 코딩 프로그램에서 코드 예제를 시험해 볼 수 있습니다.</p> +</div> + +<h2 id="안내">안내</h2> + +<p>이 모듈에서는 CSS 의 모든 기본 이론을 익히고, 몇 가지 기술을 테스트 할 수 있는 기회를 제공하는 다음과 같은 기사가 포함되어 있습니다.</p> + +<dl> + <dt><a href="/en-US/docs/Learn/CSS/First_steps/What_is_CSS">CSS 란 무엇인가?</a></dt> + <dd><strong>{{Glossary("CSS")}}</strong> (Cascading Style Sheets) 를 사용하면 멋진 웹 페이지를 만들 수 있지만 어떻게 작동합니까? 이 기사에서는 간단한 구문 예제를 통해 CSS 가 무엇인지 설명하고 언어에 대한 몇 가지 주요 용어를 다룹니다.</dd> + <dt><a href="/en-US/docs/Learn/CSS/First_steps/Getting_started">CSS 로 시작하기</a></dt> + <dd>이 기사에서는 간단한 HTML 문서를 가져와서 CSS 를 적용하여 언어에 대한 실질적인 내용을 학습합니다.</dd> + <dt><a href="/en-US/docs/Learn/CSS/First_steps/How_CSS_is_structured">CSS 의 구조</a></dt> + <dd>CSS 가 무엇인지, 그리고 CSS 의 기본 사용법에 대해 알고 있습니다. 이제 언어 자체의 구조를 조금 더 깊이 살펴볼 차례입니다. 우리는 이미 여기에서 논의된 많은 개념들을 만났습니다. 나중에 헷갈리는 개념을 발견하면 다시 이 개념으로 돌아와서 요약 할 수 있습니다.</dd> + <dt><a href="/en-US/docs/Learn/CSS/First_steps/How_CSS_works">CSS 작동 방식</a></dt> + <dd>CSS 의 기본 사항, 목적 및 간단한 스타일 시트 작성 방법을 배웠습니다. 이 강의에서는 브라우저가 CSS 와 HTML 을 가져와서 웹 페이지로 만드는 방법을 살펴 봅니다.</dd> + <dt><a href="/en-US/docs/Learn/CSS/First_steps/Using_your_new_knowledge">새로운 지식 사용</a></dt> + <dd>지난 몇 단원에서 배운 내용을 통해 CSS 를 사용하여 간단한 텍스트 문서의 서식을 지정하고 자신만의 스타일을 추가 할 수 있다는 것을 알게 될 것입니다. 이 기사는 그렇게 할 수 있는 기회를 제공합니다.</dd> +</dl> + +<h2 id="참고_항목">참고 항목</h2> + +<dl> + <dt><a href="https://teach.mozilla.org/activities/intermediate-web-lit/">중급자 웹 활용 능력 1: CSS 소개</a></dt> + <dd><em>CSS 소개</em> 모듈에서 이야기 한 많은 기술을 탐구하고 테스트하는 훌륭한 모질라 기초 과정입니다. 웹 페이지, CSS 선택자, 속성 및 값의 HTML 요소 스타일 지정에 대해 학습합니다.</dd> +</dl> diff --git a/files/ko/learn/css/first_steps/using_your_new_knowledge/index.html b/files/ko/learn/css/first_steps/using_your_new_knowledge/index.html new file mode 100644 index 0000000000..6a1795419c --- /dev/null +++ b/files/ko/learn/css/first_steps/using_your_new_knowledge/index.html @@ -0,0 +1,96 @@ +--- +title: 새로운 지식을 사용하기 +slug: Learn/CSS/First_steps/Using_your_new_knowledge +translation_of: Learn/CSS/First_steps/Using_your_new_knowledge +--- +<p>{{LearnSidebar}}{{PreviousMenu("Learn/CSS/First_steps/How_CSS_works", "Learn/CSS/First_steps")}}</p> + +<p class="summary">지난 몇 단원에서 배운 내용을 통해 CSS 를 사용하여 간단한 텍스트 문서의 서식을 지정하여 자신만의 스타일을 추가 할 수 있다는 것을 알게 될 것입니다. 이 평가는 그 기회를 제공합니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">전제조건:</th> + <td>이 평가를 시도하기 전에 나머지 CSS 기본 과목을 살펴보고 HTML 기본 사항 (<a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">HTML 소개</a> 학습) 을 이해해야 합니다.</td> + </tr> + <tr> + <th scope="row">목적:</th> + <td>CSS 를 가지고 놀면서 새로운 지식을 테스트하기</td> + </tr> + </tbody> +</table> + +<h2 id="시작점">시작점</h2> + +<p>아래의 라이브 편집기에서 작업하거나 , <a href="https://github.com/mdn/css-examples/blob/master/learn/getting-started/biog-download.html/">시작점을 다운로드</a> 하여 자신의 편집기에서 작업할 수 있습니다. 이 페이지는 HTML 과 문서 head 의 시작점 CSS 가 포함된 단일 페이지 입니다. 원하는 경우 로컬 컴퓨터에서 예제를 만들 때, 이 CSS 를 별도의 파일로 옮길수 있습니다. 또는 <a href="https://codepen.io/" rel="noopener">CodePen</a>, <a href="https://jsfiddle.net/" rel="noopener">jsFiddle</a> 또는 <a href="https://glitch.com/" rel="noopener">Glitch</a> 와 같은 온라인 도구를 사용하여 작업을 수행하십시오.</p> + +<div class="blockIndicator note"> +<p><strong>참고</strong>: 문제가 발생하면, 도움을 요청하십시오 — 이 페이지 하단의 <a href="/en-US/docs/Learn/CSS/First_steps/Using_your_new_knowledge#Assessment_or_further_help">평가 또는 추가 도움말</a> 섹션을 참조하십시오.</p> +</div> + +<h2 id="CSS_를_사용한_작업">CSS 를 사용한 작업</h2> + +<p>다음 라이브 예는 CSS 를 사용하여 스타일이 지정된 전기(biography) 를 보여줍니다. 내가 사용한 CSS 속성은 다음과 같습니다 — 각 속성은 MDN 의 속성 페이지에 연결되어 더 많은 사용 예를 제공합니다.</p> + +<ul> + <li>{{cssxref("font-family")}}</li> + <li>{{cssxref("color")}}</li> + <li>{{cssxref("border-bottom")}}</li> + <li>{{cssxref("font-weight")}}</li> + <li>{{cssxref("font-size")}}</li> + <li>{{cssxref("text-decoration")}}</li> +</ul> + +<p>나는 선택자, h1 및 h2 와 같은 스타일 요소를 혼합하여 사용했지만, 작업 제목 및 스타일을 위한 class 를 만들었습니다.</p> + +<p>CSS 를 사용하여 내가 사용한 속성 값을 변경하여 이 전기(biography) 의 모양을 변경하십시오.</p> + +<ol> + <li>CSS color 키워드인 <code>hotpink</code> 를 사용하여 h1 제목을 분홍색으로 만듭니다.</li> + <li>CSS color 키워드 <code>purple</code> 을 사용하는 10px 점선 {{cssxref("border-bottom")}} 을 제목으로 지정하십시오.</li> + <li>h2 제목을 기울임 꼴로 만듭니다.</li> + <li>연락처 세부 정보에 사용된 <code>ul</code> 에 {{cssxref("background-color")}} 를 <code>#eeeeee</code> 및 5px 의 단색 자주색 {{cssxref("border")}} 으로 만듭니다. {{cssxref("padding")}} 을 사용하여 콘텐츠를 테두리에서 밀어냅니다.</li> + <li>마우스를 가리키면 <code>green</code> 으로 만듭니다.</li> +</ol> + +<p>이 이미지와 비슷한 결과가 나옵니다.</p> + +<p><img alt="Screenshot of how the example should look after completing the assessment." src="https://mdn.mozillademos.org/files/17035/learn-css-basics-assessment.png" style="height: 1199px; width: 1104px;"></p> + +<p>그런 다음 <a href="/en-US/docs/Web/CSS/Reference">MDN CSS 참조</a> 에서 이 페이지에 언급되지 않은 일부 속성을 찾아보고 시도해 보십시오!</p> + +<p>여기에 오답이 없다는 것을 기억하십시오 — 이 단계의 학습에서는 약간의 즐거움을 가질 수 있습니다.</p> + +<p>{{EmbedGHLiveSample("css-examples/learn/getting-started/biog.html", '100%', 1600)}} </p> + +<h2 id="평가_또는_추가_도움">평가 또는 추가 도움</h2> + +<p>작업을 평가하고 싶거나 작업이 정체되어 도움을 요청하려는 경우:</p> + +<ol> + <li>작업을 <a href="https://codepen.io/" rel="noopener">CodePen</a>, <a href="https://jsfiddle.net/" rel="noopener">jsFiddle</a> 또는 <a href="https://glitch.com/" rel="noopener">Glitch</a> 와 같은 온라인 공유 가능 편집기에 입력합니다.</li> + <li><a class="external external-icon" href="https://discourse.mozilla.org/c/mdn/learn" rel="noopener">MDN 토론 포럼 학습 카데고리</a> 에 평가 및 도움을 요청하는 게시물을 작성 하십시오. 게시물에는 다음이 포함되어야 합니다: + <ul> + <li>"CSS 첫 단계에 대한 평가가 필요했습니다" 와 같은 설명적인 제목입니다.</li> + <li>당신이 이미 시도한 내용 및 당신이 우리가 무엇을 하기를 원하는지에 대한 세부 사항 입니다. 예: 당신이 정체되어 있고 도움이 필요하거나 평가를 원하는지에 대한 세부사항들.</li> + <li>온라인 공유 가능 편집기 (위의 1 단계에서 언급한) 에서 평가하거나 도움이 필요한 예에 대한 링크입니다. 이것은 좋은 습관입니다 — 코드가 보이지 않으면 코딩에 문제가 있는 사람을 돕는 것이 매우 어렵습니다.</li> + <li>실제 작업 또는 평가 페이지에 대한 링크로 도움이 필요한 질문을 찾을 수 있습니다.</li> + </ul> + </li> +</ol> + +<h2 id="다음은_뭐죠">다음은 뭐죠?</h2> + +<p>첫 번째 강의를 완료한 것을 축하합니다. 이제 CSS 에 대해 잘 이해하고 스타일 시트에서 발생하는 많은 부분을 이해할 수 있어야 합니다. 다음 강의인 <a href="/en-US/docs/Learn/CSS/Building_blocks">CSS building blocks</a> 에서는 여러 가지 주요 영역을 자세히 살펴보겠습니다.</p> + +<p>{{PreviousMenu("Learn/CSS/First_steps/How_CSS_works", "Learn/CSS/First_steps")}}</p> + +<h2 id="이번_강의에서는">이번 강의에서는</h2> + +<ol> + <li><a href="/en-US/docs/Learn/CSS/First_steps/What_is_CSS">CSS 란 무엇인가?</a></li> + <li><a href="/en-US/docs/Learn/CSS/First_steps/Getting_started">CSS 로 시작하기</a></li> + <li><a href="/en-US/docs/Learn/CSS/First_steps/How_CSS_is_structured">CSS 의 구조</a></li> + <li><a href="/en-US/docs/Learn/CSS/First_steps/How_CSS_works">CSS 작동 방식</a></li> + <li><a href="/en-US/docs/Learn/CSS/First_steps/Using_your_new_knowledge">새로운 지식을 사용하기</a></li> +</ol> diff --git a/files/ko/learn/css/first_steps/what_is_css/index.html b/files/ko/learn/css/first_steps/what_is_css/index.html new file mode 100644 index 0000000000..8467bca311 --- /dev/null +++ b/files/ko/learn/css/first_steps/what_is_css/index.html @@ -0,0 +1,119 @@ +--- +title: CSS 란 무엇인가? +slug: Learn/CSS/First_steps/What_is_CSS +translation_of: Learn/CSS/First_steps/What_is_CSS +--- +<div>{{LearnSidebar}}</div> + +<div>{{NextMenu("Learn/CSS/First_steps/Getting_started", "Learn/CSS/First_steps")}}</div> + +<p class="summary"><strong>{{Glossary("CSS")}}</strong> (Cascading Style Sheets) 를 사용하면 멋진 웹 페이지를 만들 수 있지만, 어떻게 작동합니까? 이 기사에서는 간단한 구문 예제를 통해 CSS가 무엇인지 설명하고 언어에 대한 몇 가지 주요 용어를 다룹니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">전제조건:</th> + <td>컴퓨터 기본 활용 능력, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Installing_basic_software">기본 소프트웨어 설치</a>, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Dealing_with_files">파일 작업</a> 에 대한 기본 지식 및 HTML 기본 사항 (<a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">HTML 소개</a> 학습)</td> + </tr> + <tr> + <th scope="row">목적:</th> + <td>CSS가 무엇인지 배우기.</td> + </tr> + </tbody> +</table> + +<p><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">HTML 소개</a> 단원에서는 HTML 이 무엇인지, 그리고 문서를 마크 업하는 데 사용되는 방법에 대해 설명했습니다. 이 문서는 웹 브라우저에서 읽을 수 있습니다. 제목은 일반 텍스트보다 크게 보이며, 단락은 줄바꿈이 되고 공백이 있습니다. 링크는 텍스트의 나머지 부분과 구분하기 위해 색상과 밑줄이 표시됩니다. 현재 보고 있는 것은 브라우저의 기본 스타일입니다. 페이지 작성자가 명시적인 스타일을 지정하지 않은 경우에도 기본적으로 읽을 수 있도록 브라우저가 HTML에 적용하는 매우 기본적인 스타일입니다.</p> + +<p><img alt="The default styles used by a browser" src="https://mdn.mozillademos.org/files/16493/html-example.png" style="border: 1px solid #cccccc; height: 594px; width: 1385px;"></p> + +<p>그러나, 모든 웹 사이트가 그렇게 보인다면 웹은 지루한 곳이 될 것입니다. CSS를 사용하면 브라우저에서 HTML 요소의 모양을 정확하게 제어하고 원하는 디자인을 사용하여 마크 업을 표시할 수 있습니다.</p> + +<h2 id="CSS_란_무엇입니까">CSS 란 무엇입니까?</h2> + +<p>앞에서 언급했듯이, CSS 는 사용자에게 문서를 표시하는 방법을 지정하는 언어입니다 — 스타일, 레이아웃 등.</p> + +<p><strong>문서</strong>는 일반적으로 마크 업 언어를 사용하여 구성된 텍스트 파일입니다 — {{Glossary("HTML")}} 이 가장 일반적인 마크 업 언어이지만, {{Glossary("SVG")}} 또는 {{Glossary("XML")}} 과 같은 다른 마크 업 언어를 사용할 수도 있습니다.</p> + +<p>사용자에게 문서를 <strong>제공 한다는 것</strong>은 대상이 사용 할 수 있는 형식으로 문서를 변환하는 것을 의미합니다. {{Glossary("browser","Browsers")}}, {{Glossary("Mozilla Firefox","Firefox")}}, {{Glossary("Google Chrome","Chrome")}} 또는 {{Glossary("Microsoft Edge","Edge")}} 는 컴퓨터 화면, 프로젝터 또는 프린터 등의 문서를 시각적으로 표시하도록 설계되었습니다.</p> + +<div class="blockIndicator note"> +<p><strong>참고</strong>: 브라우저는 {{Glossary("User agent","user agent")}} 라고도 하며, 기본적으로 컴퓨터 시스템 내부의 개인을 나타내는 컴퓨터 프로그램을 의미합니다. 브라우저는 CSS 에 대해 이야기 할 때, 우리가 생각하는 주요 유형의 user agent 이지만, 유일한 브라우저는 아닙니다. HTML 및 CSS 문서를 인쇄할 PDF로 변환하는 것과 같은 사용 가능한 다른 사용자 user agent 가 있습니다.</p> +</div> + +<p>CSS 는 매우 기본적인 텍스트 문서 스타일링에 사용될 수 있습니다 — 예를 들어, 제목 및 링크의 <a href="/en-US/docs/Web/CSS/color_value">색상</a> 과 <a href="/en-US/docs/Web/CSS/font-size">크기</a> 변경. 또한, 레이아웃을 만드는 데 사용 할 수 있습니다 — 예를 들어, <a href="/en-US/docs/Web/CSS/Layout_cookbook/Column_layouts">단일 텍스트 열을 변환</a> (기본 콘텐츠 영역과 관련 정보에 대한 사이드 바가 있는 레이아웃으로) 하는 등 레이아웃을 만드는 데 사용 할 수 있습니다. <a href="/en-US/docs/Web/CSS/CSS_Animations">애니메이션</a> 과 같은 효과에도 사용 할 수 있습니다. 구체적인 예는 이 단락의 링크를 살펴 보십시오.</p> + +<h2 id="CSS_구문">CSS 구문</h2> + +<p>CSS 는 규칙 기반 언어입니다 — 웹 페이지의 특정 요소 또는 요소 그룹에 적용할 스타일 그룹을 지정하는 규칙을 정의합니다. 예를 들어 "내 페이지의 제목이 빨간색이며 큰 텍스트로 표시 되기를 원합니다."</p> + +<p>다음 코드는 위에서 설명한 스타일을 실행 하는 매우 간단한 CSS 규칙을 보여줍니다:</p> + +<pre class="brush: css">h1 { + color: red; + font-size: 5em; +}</pre> + +<p>규칙은 {{Glossary("CSS Selector", "selector")}} 와 함께 열립니다. 스타일을 지정할 HTML 요소를 <em><strong>선택</strong> </em>합니다. 이 경우 level 1 제목 ({{htmlelement("h1")}}) 을 스타일링합니다.</p> + +<p>그런 다음 중괄호 <code>{ }</code> 가 있습니다. 그 안에는 <strong>속성</strong>과 <strong>값</strong> 쌍의 형태를 취하는 하나 이상의 <strong>선언</strong>이 있습니다. 각 쌍은 우리가 선택한 요소의 속성을 지정하고 속성에 부여할 값을 지정합니다.</p> + +<p>콜론 앞에는, 속성이 있고 콜론 뒤에는 값이 있습니다. CSS {{Glossary("property/CSS","properties")}} 는 지정되는 속성에 따라 허용되는 값이 다릅니다. 이 예제에서는 다양한 <a href="/en-US/docs/Learn/CSS/Building_blocks/Values_and_units#Color">색상 값</a> 을 사용 할 수 있는 <code>color</code> 속성이 있습니다. 또한 <code>font-size</code> 속성도 있습니다. 이 속성은 다양한 <a href="/en-US/docs/Learn/CSS/Building_blocks/Values_and_units#Numbers_lengths_and_percentages">크기 단위</a> 를 값으로 사용 할 수 있습니다.</p> + +<p>CSS 스타일 시트에는 여러 규칙이 하나씩 포함되어 있습니다.</p> + +<pre class="brush: css">h1 { + color: red; + font-size: 5em; +} + +p { + color: black; +}</pre> + +<p>일부 값은 빨리 배운다는 것을 알게 될 것이고, 반면에 다른 값은 여러분이 찾아야 할 것입니다. MDN 의 개별 속성 페이지는 잊었을 때 또는 값으로 사용 할 수 있는 다른 것을 알고자 할 때 속성과 해당 값을 빠르게 찾을 수 있는 방법을 제공합니다.</p> + +<div class="blockIndicator note"> +<p><strong>참고</strong>: MDN <a href="/en-US/docs/Web/CSS/Reference">CSS 참조</a> 에 나열된 모든 CSS 속성 페이지 (다른 CSS 기능과 함께) 에 대한 링크를 찾을 수 있습니다. 또는, CSS 기능에 대한 자세한 정보를 찾아야 할 때 마다, 자주 사용하는 검색 엔진에서 "mdn <em>css-feature-name</em>" 을 검색하는 데 익숙해야 합니다. 예를 들어, "mdn color" 및 "mdn font-size" 를 검색해 보십시오!</p> +</div> + +<h2 id="CSS_Modules">CSS Modules</h2> + +<p>CSS 를 사용하여 스타일을 지정할 수 있는 것이 너무 많으므로, 언어는 <em>module</em> 로 분류됩니다. MDN 을 탐색할 때 이러한 module 에 대한 참조가 표시되면, 많은 설명서 페이지가 특정 modul 을 중심으로 구성되어 있습니다. 예를 들어, <a href="/en-US/docs/Web/CSS/CSS_Backgrounds_and_Borders">배경 및 테두리</a> module 에 대한 MDN 참조를 통해 그 용도가 무엇이며, 그 용도에 포함된 다른 속성 및 기타 기능을 확인할 수 있습니다. 또한 기술을 정의하는 <em>CSS Specification</em> 에 대한 링크를 찾을 수 있습니다 (아래 참조).</p> + +<p>이 단계에서는 CSS 가 어떻게 구성되어 있는지에 대해 너무 걱정할 필요가 없지만, 예를 들어 특정 속성이 다른 유사한 것들 중에서 발견될 가능성이 높기 때문에, 동일한 specification 에 있을 수 있다는 것을 알고 있다면 정보를 쉽게 찾을 수 있습니다.</p> + +<p>구체적인 예를 들어, 배경 및 테두리 module 로 돌아가 보겠습니다 — 이 module 에서 <code><a href="/en-US/docs/Web/CSS/background-color">background-color</a></code> 및 <code><a href="/en-US/docs/Web/CSS/border-color">border-color</a></code> 속성을 정의하는 것이 논리적이라고 생각 할 수 있습니다. 당신이 옳을 겁니다.</p> + +<h3 id="CSS_Specifications">CSS Specifications</h3> + +<p>모든 웹 표준 기술 (HTML, CSS, JavaScript 등.) 은 표준 조직 ({{glossary("W3C")}}, {{glossary("WHATWG")}}, {{glossary("ECMA")}} 또는 {{glossary("Khronos")}} 와 같은) 이 게시한 specifications (또는 단순히 "specs") 이라는 거대한 문서로 정의됩니다. 이러한 기술의 작동 방식을 정확하게 정의하십시오.</p> + +<p>CSS 는 다르지 않습니다 — W3C 내에서 <a href="https://www.w3.org/Style/CSS/">CSS Working Group</a> 이라는 곳에서 개발 했습니다. 이 그룹은 브라우저 공급 업체 및 CSS 에 관심이 있는 다른 회사의 대표로 구성됩니다. 독립적인 목소리로 행동하는 <strong><em>초청된 전문가</em></strong> 로 알려진 다른 사람들도 있습니다. 그들은 회원 조직에 연결되어 있지 않습니다.</p> + +<p>새로운 CSS 기능은 CSS Working Group 에 의해 개발되거나 지정됩니다. 때로는 특정 브라우저가 일부 기능에 관심이 있기 때문에 웹 디자이너와 개발자가 기능을 요구하고, 때로는 실무 그룹 자체가 요구 사항을 식별했기 때문입니다. CSS 는 지속적으로 개발 중이며 새로운 기능을 사용할 수 있습니다. 그러나 CSS 의 중요한 점은 모든 사람이 오래된 웹 사이트를 망가뜨릴 수 있는 방식으로 변경하지 않도록 매우 열심히 노력한다는 것입니다. 현재 사용 가능한 제한된 CSS 를 사용하여 2000년에 구축된 웹 사이트는 여전히 브라우저에서 사용 할 수 있습니다!</p> + +<p>CSS 를 처음 첩하는 사람들은, CSS specs 이 압도적이라고 생각할 것입니다 — 웹 개발자가 CSS 를 이해하기 위해 읽는 것이 아니라 엔지니어가 user agents 의 기능에 대한 지원을 구현하는 데 사용하기 위한 것입니다. 많은 숙련된 개발자가 MDN 설명서나 기타 자습서를 참조하는 것이 좋습니다. 그러나 사용중인 CSS, 브라우저 지원 (아래 참조) 및 specs 간의 관계를 이해하고 존재한다는 것을 아는 것이 좋습니다.</p> + +<h2 id="브라우저_지원">브라우저 지원</h2> + +<p>CSS 가 지정되면 하나 이상의 브라우저가 이를 구현한 경우에만 웹 페이지를 개발하는 데 유용합니다. 이것은 CSS 파일의 명령을 화면에 출력할 수 있는 것으로 바꾸도록 코드가 작성되었음을 의미합니다. <a href="/en-US/docs/Learn/CSS/First_steps/How_CSS_works">CSS 작동 방식</a> 수업에서 이것에 대해 자세히 살펴보겠습니다. 모든 브라우저가 동시에 기능을 구현하는 것은 드문 일이므로 일반적으로 일부 브라우저에서는 CSS 의 일부를 사용할 수 있고, 다른 브라우저에서는 사용할 수 없는 경우가 있습니다. 이러한 이유로, 구현 상태를 확인할 수 있는 것이 유용합니다. MDN 의 각 속성 페이지에서 관심있는 속성의 상태를 볼 수 있으므로 웹 사이트에서 해당 속성을 사용할 수 있는지 알 수 있습니다.</p> + +<p>다음은 CSS <code><a href="/en-US/docs/Web/CSS/font-family">font-family</a></code> 속성에 대한 데이터 차트입니다.</p> + +<p>{{Compat("css.properties.font-family")}}</p> + +<h2 id="다음은_뭐죠">다음은 뭐죠</h2> + +<p>CSS 가 무엇인지 이해했으니, 이제 <a href="/en-US/docs/Learn/CSS/First_steps/Getting_started">CSS 시작하기</a> 로 넘어가서 CSS 를 직접 작성할 수 있습니다.</p> + +<p>{{NextMenu("Learn/CSS/First_steps/Getting_started", "Learn/CSS/First_steps")}}</p> + +<h2 id="이번_강의에서는">이번 강의에서는</h2> + +<ol> + <li><a href="/en-US/docs/Learn/CSS/First_steps/What_is_CSS">CSS 란 무엇인가?</a></li> + <li><a href="/en-US/docs/Learn/CSS/First_steps/Getting_started">CSS 로 시작하기</a></li> + <li><a href="/en-US/docs/Learn/CSS/First_steps/How_CSS_is_structured">CSS 의 구조</a></li> + <li><a href="/en-US/docs/Learn/CSS/First_steps/How_CSS_works">CSS 작동 방식</a></li> + <li><a href="/en-US/docs/Learn/CSS/First_steps/Using_your_new_knowledge">새로운 지식 사용</a></li> +</ol> diff --git a/files/ko/learn/css/howto/generated_content/index.html b/files/ko/learn/css/howto/generated_content/index.html new file mode 100644 index 0000000000..216305f889 --- /dev/null +++ b/files/ko/learn/css/howto/generated_content/index.html @@ -0,0 +1,123 @@ +--- +title: 내용물 +slug: Learn/CSS/Howto/Generated_content +translation_of: Learn/CSS/Howto/Generated_content +--- +<p>{{ CSSTutorialTOC() }}</p> +<div class="warning"> + <strong>중요</strong>: 번역은 제가 필요한 부분 및 확인 가능한 부분만 진행 하였으며 변역된 날자는(2013/03/18)이며 문서 변경이 잦아 오늘 이후는 원문과 번역이 다를 수 있습니다. 참고하세요. 미 번역/변경된 부분은 추가로 다른 분이 해 주실 것으로 믿습니다.</div> +<p>{{ previousPage("/en-US/docs/CSS/Getting_Started/Color", "색상") }}<span class="seoSummary"><a href="/en/CSS/Getting_Started" title="en/CSS/Getting Started">CSS 시작하기</a> 안내서 9번째 장; 이번에는 CSS에서</span><span class="seoSummary">Document에 표시될 내용물을 추가 하는 </span><span class="seoSummary">방법을 알아보자. stylesheet를 수정해서 텍스트 내용과 이미지를 수정해 보자.</span></p> +<h2 class="clearLeft" id="정보_내용물">정보: 내용물</h2> +<p>CSS사용상의 가장 큰 장점은 document의 스타일과 내용물을 분리할 수 있도록 도와준다. 하지만 아직은 Document의 일부가 아니라 Stylesheet의 일부로서 존재해야 이치가 맞아 보이는 내용들도 있다.</p> +<p>stylesheet에 놓여진 내용물(content)은 텍스트나 이미지로 구성될 수 있다. Document의 구조와 밀접하게 연결된 내용물(content)은 stylesheet에 명시 할수 있다.</p> +<div class="tuto_details"> + <div class="tuto_type"> + 좀더 자세히</div> + <p>stylesheet에 내용물(content)을 표시하는 것은 복잡한 문제를 발생 시킬 수도 있다. 예를 들면, 동일한 stylesheet를 사용하는 여러 언어를 지원하는 Document의 경우이다. 만약 stylesheet일 일부분이 번역되어야 하는 경우가 있다면 이 부분은 stylesheet와는 분리된 파일로 저장하고 Document 언어에 맞는 파일이 연결 되도록 할당 해야 한다.</p> + <p>이미지나 심볼 혹은 모든 언어나 문화에 공통으로 사용되는 것을 쓴다면 이러한 문제는 발생하지 않는다.</p> + <p>stylesheet에 작성된 내용물(Content)은 DOM의 일부가 될 수는 없다.</p> +</div> +<h3 id="텍스트_내용물">텍스트 내용물</h3> +<p>CSS는 element 전후로 텍스트 내용물을 넣을 수 있다. 이를 위해서는, 규칙을 만들고 {{ cssxref(":before") }}나 {{ cssxref(":after") }}를 구분자로 넣고 여기에 추가 하라. 선언부에 {{ cssxref("content") }}속성선언과 그 값으로 텍스트를 추가 하라.</p> +<div class="tuto_example"> + <div class="tuto_type"> + 예제</div> + <p>이 규칙은 모든 'ref' class element 앞에 <span style="font-weight: bold; color: navy;">'Reference :'</span>텍스트를 추가 한다.</p> + <pre class="brush:css">.ref:before { + font-weight: bold; + color: navy; + content: "Reference: "; +} +</pre> +</div> +<div class="tuto_details"> + <div class="tuto_type"> + 좀더 자세히</div> + <p>stylesheet의 코드셋은 UTF-8이 기본이다. 그러나 링크 내나 stylesheet내 혹은 다른 방법으로 코드셋을 설정 할 수 있다. CSS 사양서의 <a class="external" href="http://www.w3.org/TR/CSS21/syndata.html#q23">4.4 CSS style sheet representation</a>를 참고 하라.</p> + <p>독특한 캐릭터도 백슬레쉬(\)와 함께 사용하는 escape 표시법으로 사용 할 수 있다. 예를 들어 \256B는 블랙퀸 체스 심볼(♛)이다. 좀더 자세히는 CSS 사양서의 <a class="external" href="http://www.w3.org/TR/CSS21/syndata.html#q24">문자열 코드표에 없는 문자열 참조</a>나 CSS 사양서의 <a class="external" href="http://www.w3.org/TR/CSS21/syndata.html#q6">Characters and case</a>를 참고하라.</p> +</div> +<h3 id="이미지_내용물">이미지 내용물</h3> +<p>element 전/후로 이미지를 추가 하려면, {{ cssxref("content") }}속성에 이미지의 URL을 넣어라.</p> +<div class="tuto_example"> + <div class="tuto_type"> + 예제</div> + <p>이 규칙은 <code>'glossary</code>' class 다음에 공백과 하나의 아이콘을 추가한다.</p> + <pre class="brush:css">a.glossary:after {content: " " url("../images/glossary-icon.gif");} +</pre> +</div> +<p>element의 배경으로 이미지를 추가 하고자 한다면, {{ cssxref("background") }}속성 값에 이미지의 URL을 할당 하라. 이것이 배경색이나, 이미지를 설정하거나, 이미지를 반복하거나 혹은 다른 사항을 설정하는 단순한 방법이다.</p> +<div class="tuto_example"> + <div class="tuto_type"> + 예제</div> + <p>이 규칙은 특정 element의 배경을 이미지 URL로 지정 하는 것이다.</p> + <p>이 설렉터느 element의 id를 나타낸다. <code>'no-repeat'</code> 값은 이미지가 한번만 나타나는 것을 말한다.</p> + <pre class="brush:css">#sidebar-box {background: url("../images/sidebar-ground.png") no-repeat;} +</pre> +</div> +<div class="tuto_details"> + <div class="tuto_type"> + 좀더 자세히</div> + <p>배경설정에 관한 특별한 속성이나 이미지 설정 옵션에 관한 자세한 정보는 {{ cssxref("background") }} 참조 페이지를 보라.</p> +</div> +<h2 id="액션_배경_이미지_추가_하기">액션: 배경 이미지 추가 하기</h2> +<p>이 이미지는 아래쪽에 파란색 줄이 있는 흰사각형이다.:</p> +<table style="border: 2px solid #ccc;"> + <tbody> + <tr> + <td><img alt="Image:Blue-rule.png" class="internal" src="/@api/deki/files/47/=Blue-rule.png"></td> + </tr> + </tbody> +</table> +<ol> + <li>이 이미지를 다운 받아 예제파일들이 있는 폴더에 저장하라. (이미지에서 왼쪽 클릭을 하여 나타나는 메뉴에서 "다른 이름으로 사진저장"을 선택하여 예제가 있는 폴더를 선택하여 저장)</li> + <li>CSS파일을 열어 아래 규칙을 body부분에 추가 하여 전체 배경으로 해당 이미지를 설정하라. + <pre class="brush:css">background: url("Blue-rule.png"); +</pre> + <p>일단 위의 값은 이미지를 반복적으로 보여주는데, 기본 설정이므로 따로 표시 해 줄 필요는 없다. 이미지는 수직/수평적으로 반복되어 아래와 같이 편지지 같은 화면을 제공한다.</p> + <div style="position: relative; width: 24em; height: 11em; border: 2px outset #36b; overflow: hidden;"> + <p style="margin: 0px;"><img alt="Image:Blue-rule-ground.png" class="internal" src="/@api/deki/files/46/=Blue-rule-ground.png"></p> + <div style="position: absolute; top: 0px; left: 0px; border: none; margin: 0px; padding: .5em 0px 0px 1em; font: 16px 'Comic Sams MS', cursive; color: blue; background-color: transparent;"> + <div style="font-style: italic; width: 24em;"> + <p><strong style="color: red; background-color: #ddf; font: 200% serif;">C</strong>ascading <strong style="color: green; background-color: #ddf; font: 200% serif;">S</strong>tyle <strong style="color: green; background-color: #ddf; font: 200% serif;">S</strong>heets</p> + </div> + <div style="font-style: normal; padding-top: 2px; height: 8em;"> + <p><strong style="color: red; background-color: #ddf; font: 200% serif;">C</strong>ascading <strong style="color: red; background-color: #ddf; font: 200% serif;">S</strong>tyle <strong style="color: red; background-color: #ddf; font: 200% serif;">S</strong>heets</p> + </div> + </div> + </div> + </li> +</ol> +<div class="tuto_example"> + <div class="tuto_type"> + 도전</div> + <p>아래 아미지를 다운 받아보라.</p> + <table style="border: 2px solid #ccc;"> + <tbody> + <tr> + <td><img alt="Image:Yellow-pin.png" class="internal" src="/@api/deki/files/490/=Yellow-pin.png"></td> + </tr> + </tbody> + </table> + <p>Stylesheet에 하나의 규칙을 추가 하여 아래와 같이 각라인 맨 앞에 나타나도록 하라.</p> + <div style="position: relative; width: 24em; height: 11em; border: 2px outset #36b; overflow: hidden;"> + <p style="margin: 0px;"><img alt="Image:Blue-rule-ground.png" class="internal" src="/@api/deki/files/46/=Blue-rule-ground.png"></p> + <div style="position: absolute; top: 0px; left: 0px; border: none; margin: 0px; padding: .5em 0px 0px 1em; font: 16px 'Comic Sams MS', cursive; color: blue; background-color: transparent;"> + <div style="font-style: italic; width: 24em; padding-top: 8px;"> + <img alt="image:Yellow-pin.png" class="internal" src="/@api/deki/files/490/=Yellow-pin.png"> <strong style="color: red; background-color: #ddf; font: 200% serif;">C</strong>ascading <strong style="color: green; background-color: #ddf; font: 200% serif;">S</strong>tyle <strong style="color: green; background-color: #ddf; font: 200% serif;">S</strong>heets</div> + <div style="font-style: normal; padding-top: 12px; height: 8em;"> + <img alt="image:Yellow-pin.png" class="internal" src="/@api/deki/files/490/=Yellow-pin.png"> <strong style="color: red; background-color: #ddf; font: 200% serif;">C</strong>ascading <strong style="color: red; background-color: #ddf; font: 200% serif;">S</strong>tyle <strong style="color: red; background-color: #ddf; font: 200% serif;">S</strong>heets</div> + </div> + </div> + <div class="tuto_details" id="tutochallenge"> + <div class="tuto_type"> + Possible solution</div> + <p>Add this rule to your stylesheet:</p> + <pre class="brush: css">p:before{ + content: url("yellow-pin.png"); +} +</pre> + <p> </p> + <a class="hideAnswer" href="#challenge">Hide solution</a></div> + <a href="#tutochallenge" title="Display a possible solution for the challenge">정답 확인.</a></div> +<h2 id="다음에는">다음에는?</h2> +<p>{{ nextPage("/en-US/docs/CSS/Getting_Started/Lists", "리스트") }}Stylesheet에 내용물을 추가 하는 일반 방법으로 리스트로 표기하는 방법이 있다. 다음장에는 <a href="/en-US/docs/CSS/Getting_Started/Lists" title="/en-US/docs/CSS/Getting_Started/Lists">specify style for 리스트 elements를 위한 스타일 표기법에 대해 알아보자.</a></p> diff --git a/files/ko/learn/css/howto/index.html b/files/ko/learn/css/howto/index.html new file mode 100644 index 0000000000..cd63db7d1a --- /dev/null +++ b/files/ko/learn/css/howto/index.html @@ -0,0 +1,86 @@ +--- +title: 일반적인 CSS 문제 해결하기 +slug: Learn/CSS/Howto +translation_of: Learn/CSS/Howto +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">다음 링크들은 일반적인 CSS 문제들에 대한 해결방법을 제공합니다.</p> + +<h2 id="일반적인_사례">일반적인 사례</h2> + +<div class="column-container"> +<div class="column-half"> +<h3 id="Basics">Basics</h3> + +<ul> + <li><a href="/en-US/Learn/CSS/Introduction_to_CSS/How_CSS_works#How_to_apply_your_CSS_to_your_HTML">How to apply CSS to HTML</a></li> + <li><a href="/en-US/Learn/CSS/Introduction_to_CSS/Syntax#White_space">How to use whitespace in CSS</a></li> + <li><a href="/en-US/Learn/CSS/Introduction_to_CSS/Syntax#Comments">How to write comments in CSS</a></li> + <li><a href="/en-US/Learn/CSS/Introduction_to_CSS/Selectors#Simple_selectors">How to select elements via element name, class or ID</a></li> + <li><a href="/en-US/Learn/CSS/Introduction_to_CSS/Selectors#Attribute_selectors">How to select elements via attribute name and content</a></li> + <li><a href="/en-US/Learn/CSS/Introduction_to_CSS/Selectors#Pseudo-classes">How to use pseudo-classes</a></li> + <li><a href="/en-US/Learn/CSS/Introduction_to_CSS/Selectors#Pseudo-elements">How to use pseudo-elements</a></li> + <li><a href="/en-US/Learn/CSS/Introduction_to_CSS/Selectors#Multiple_selectors_on_one_rule">How to apply multiple selectors to the same rule</a></li> + <li><a href="/en-US/Learn/CSS/Introduction_to_CSS/Values_and_units#Colors">How to specify colors in CSS</a></li> + <li><a href="/en-US/Learn/CSS/Introduction_to_CSS/Debugging_CSS#Inspecting_the_DOM_and_CSS">How to debug CSS in the browser</a></li> +</ul> + +<h3 id="CSS_and_text">CSS and text</h3> + +<ul> + <li><a href="/en-US/docs/Learn/CSS/Styling_text/Fundamentals">How to style text</a></li> + <li><a href="/en-US/docs/Learn/CSS/Styling_text/Styling_lists">How to customize a list of elements</a></li> + <li><a href="/en-US/Learn/CSS/Styling_text/Styling_links">How to style links</a></li> + <li><a href="/en-US/Learn/CSS/Styling_text/Fundamentals#Text_drop_shadows">How to add shadows to text</a></li> +</ul> +</div> + +<div class="column-half"> +<h3 id="Boxes_and_layouts">Boxes and layouts</h3> + +<ul> + <li><a href="/en-US/Learn/CSS/Introduction_to_CSS/Box_model#Box_properties">How to size CSS boxes</a></li> + <li><a href="/en-US/Learn/CSS/Introduction_to_CSS/Box_model#Overflow">How to control overflowing content</a></li> + <li><a href="/en-US/Learn/CSS/Introduction_to_CSS/Box_model#Background_clip">How to control the part of a CSS box that the background is drawn under</a></li> + <li><a href="/en-US/Learn/CSS/Introduction_to_CSS/Box_model#Types_of_CSS_boxes">How do I define inline, block, and inline-block?</a></li> + <li><a href="/en-US/docs/Learn/CSS/Howto/create_fancy_boxes">How to create fancy boxes</a> (also see the <a href="/en-US/docs/Learn/CSS/Styling_boxes">Styling boxes</a> module, generally).</li> + <li><a href="/en-US/Learn/CSS/Introduction_to_CSS/Box_model#Background_clip">How to use <code>background-clip</code> to control how much of the box your background image covers</a>.</li> + <li><a href="/en-US/Learn/CSS/Styling_boxes/Box_model_recap#Changing_the_box_model_completely">How to change the box model completely using <code>box-sizing</code></a></li> + <li><a href="/en-US/Learn/CSS/Styling_boxes/Backgrounds">How to control backgrounds</a></li> + <li><a href="/en-US/Learn/CSS/Styling_boxes/Borders">How to control borders</a></li> + <li><a href="/en-US/Learn/CSS/Styling_boxes/Styling_tables">How to style an HTML table</a></li> + <li><a href="/en-US/Learn/CSS/Styling_boxes/Advanced_box_effects#Box_shadows">How to add shadows to boxes</a></li> +</ul> +</div> +</div> + +<h2 id="Uncommon_and_advanced_techniques">Uncommon and advanced techniques</h2> + +<p>CSS allows very advanced design techniques. These articles help demistify the harder use cases you may face.</p> + +<h3 id="General">General</h3> + +<ul> + <li><a href="/en-US/Learn/CSS/Introduction_to_CSS/Cascade_and_inheritance#Specificity">How to calculate specificity of a CSS selector</a></li> + <li><a href="/en-US/Learn/CSS/Introduction_to_CSS/Cascade_and_inheritance#Controlling_inheritance">How to control inheritance in CSS</a></li> +</ul> + +<h3 id="Advanced_effects">Advanced effects</h3> + +<ul> + <li><a href="/en-US/Learn/CSS/Styling_boxes/Advanced_box_effects#Filters">How to use filters in CSS</a></li> + <li><a href="/en-US/Learn/CSS/Styling_boxes/Advanced_box_effects#Blend_modes">How to use blend modes in CSS</a></li> +</ul> + +<h3 id="Layout">Layout</h3> + +<ul> + <li><a href="/en-US/docs/Web/Guide/CSS/Flexible_boxes">Using CSS flexible boxes</a></li> + <li><a href="/en-US/docs/Web/Guide/CSS/Using_multi-column_layouts" title="/en-US/docs/Web/Guide/CSS/Using_multi-column_layouts">Using CSS multi-column layouts</a></li> + <li><a href="/en-US/docs/Web/Guide/CSS/Getting_started/Content">Using CSS generated content</a></li> +</ul> + +<h2 id="See_also">See also</h2> + +<p><a href="/en-US/docs/Learn/CSS/Howto/CSS_FAQ">CSS FAQ</a> — A variety of topics: from debugging to selector usage.</p> diff --git a/files/ko/learn/css/index.html b/files/ko/learn/css/index.html new file mode 100644 index 0000000000..7b7c715da8 --- /dev/null +++ b/files/ko/learn/css/index.html @@ -0,0 +1,60 @@ +--- +title: CSS를 이용한 HTML 스타일링 익히기 +slug: Learn/CSS +tags: + - Beginner + - CSS + - CodingScripting + - Landing + - Topic +translation_of: Learn/CSS +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">{{glossary("CSS")}}(Cascading Stylesheets – 종속형 스타일시트)는 {{glossary("HTML")}}을 익힌 후 가장 먼저 배워야할 웹기술입니다. HTML이 콘텐츠의 구조와 의미를 정의하는 반면 CSS는 스타일과 레이아웃을 지정합니다. 예를 들어, CSS를 사용하면 콘텐츠의 글꼴, 색상, 크기 및 간격을 변경하거나, 여러 개의 열로 분할하거나, 애니메이션이나 기타 장식 효과를 추가할 수 있습니다.</p> + +<h2 id="학습_경로">학습 경로</h2> + +<p>CSS에 도전하기 전에 HTML의 기초를 익혀야 합니다. 먼저 <a href="/ko/docs/Learn/HTML/Introduction_to_HTML">HTML 소개</a>를 진행하면서 다음을 익히시는게 좋습니다.</p> + +<ul> + <li><a href="/ko/docs/Learn/CSS/Introduction_to_CSS">CSS 소개</a>부터 시작하는 CSS</li> + <li>고급 <a href="/ko/Learn/HTML#구성">HTML 주제</a></li> + <li><a href="/ko/docs/Learn/JavaScript">JavaScript</a> 및 웹페이지에 동적 기능을 추가하는 법</li> +</ul> + +<p>HTML의 기본 원리를 이해하고 나면, HTML과 CSS 사이를 왕복하며 동시에 학습하는걸 추천드립니다. HTML은 CSS를 활용할 때 훨씬 흥미롭고 재미있으며, HTML을 모르고는 CSS를 제대로 배울 수 없기 때문입니다.</p> + +<p>이 주제를 시작하기 전에, 컴퓨터의 사용법과 웹을 둘러보는 일이 익숙해야 합니다. <a href="/ko/docs/Learn/Getting_started_with_the_web/Installing_basic_software">기본 소프트웨어 설치하기</a>에서 설명하는 기본적인 작업 환경을 갖춰야 하고, <a href="/ko/docs/Learn/Getting_started_with_the_web/Dealing_with_files">파일 다루기</a>에서 설명하는 파일 생성 및 관리도 이해해야 합니다. 두 안내서 모두 처음 시작하는 분을 위한 <a href="/ko/docs/Learn/Getting_started_with_the_web">Web과 함께 시작하기</a>의 일부분이죠.</p> + +<p>본 주제를 시작하기 전에 <a href="/ko/docs/Learn/Getting_started_with_the_web">Web과 함께 시작하기</a>를 먼저 해보시는게 좋겠습니다. 그러나 CSS 기초 글에서 다루는걸 여기 <a href="/ko/docs/Learn/CSS/Introduction_to_CSS">CSS 소개</a>에서 훨씬 상세하게 다루므로 필수는 아닙니다.</p> + +<h2 id="구성">구성</h2> + +<p>아래는 추천 순서로 정렬한 본 주제의 구성입니다. 첫 항목부터 시작하세요.</p> + +<dl> + <dt><a href="/ko/docs/Learn/CSS/Introduction_to_CSS">CSS 소개</a></dt> + <dd>CSS 작동 원리에 대한 기초로, 선택자와 속성, CSS 규칙을 쓰는 법, HTML에 적용하기, 길이나 색상 등 단위를 특정하는 법, 종속과 상속, 박스 모델의 기초, CSS 디버그 등을 다룹니다.</dd> + <dt><a href="/ko/docs/Learn/CSS/Styling_text">텍스트 스타일링</a></dt> + <dd>여기서 글꼴, 굵기 및 기울임꼴, 줄과 문자 간격, 그림자 및 기타 텍스트 기능 설정을 비롯한 텍스트 스타일링 기본 사항을 살펴 봅니다. 페이지에 맞춤 글꼴을 적용하거나 목록 및 링크에 스타일을 적용할 수도 있습니다.</dd> + <dt><a href="/ko/docs/Learn/CSS/Styling_boxes">박스 스타일링</a></dt> + <dd>다음으로 웹페이지 레이아웃을 위한 기본 단계 중 하나인 박스 스타일링을 살펴 봅니다. 먼저 박스 모델을 다시 요약하여 설명한 후, 내부 여백(padding), 테두리(borders) 및 외부 여백(margins)을 설정하거나 사용자 지정 배경색, 이미지 및 기타 기능을 설정하고, 박스에 그림자나 필터와 같은 멋진 기능을 설정하는 등 상자 레이아웃을 제어하는 법을 알아봅니다.</dd> + <dt><a href="/ko/docs/Learn/CSS/CSS_layout">CSS 레이아웃</a></dt> + <dd>이 시점에서 이미 CSS 기초, 텍스트 스타일링 및 콘텐트가 포함된 박스의 스타일링 및 조작을 살펴보았습니다. 이제는 박스를 뷰포트(viewport) 또는 다른 박스와 관련하여 올바른 위치에 배치하는 방법을 살펴볼 시간입니다. 필요한 사전 요구 사항을 포함하여, CSS 레이아웃, 디스플레이(display) 속성의 다양한 설정, 플로트(float) 및 위치 지정(positioning)과 관련된 기존 레이아웃 방식과 더불어 유동적 박스(flexbox) 같은 새롭고 놀라운 레이아웃 도구를 깊게 살펴봅니다.</dd> + <dt>반응형 디자인 (TBD)</dt> + <dd>요즘은 다양한 장치로 웹을 탐색하기 때문에 <a href="/ko/docs/Web/Guide/Responsive_design">반응형 웹 디자인</a>(RWD; Responsive Web Design)은 핵심적인 웹 개발 기술이 되었습니다. 이 모듈에서는 반응형 웹 디자인의 기본 원칙과 도구들을 다루며, 화면 너비, 방향, 해상도와 같은 장치 특성에 따라 다른 CSS를 적용하는 방법을 설명합니다. 그리고 이런 특성에 따라 다양한 비디오와 이미지를 제공할 수 있게 하는 기술을 탐구합니다.</dd> +</dl> + +<h2 id="CSS로_일상적인_문제_해결하기">CSS로 일상적인 문제 해결하기</h2> + +<p><a href="/ko/docs/Learn/CSS/Howto">CSS를 사용하여 일반적인 문제 해결하기</a>는 웹페이지를 만들 때의 매우 흔한 문제들을 CSS를 사용해 해결하는 방법을 살펴보는 섹션들의 링크를 제공합니다.</p> + +<p>시작부터 가장 많이 하게 되는 일은 HTML 요소들(elements)의 색상과 배경색을 지정하고, 크기나 모양 또는 위치를 변경하고, 테두리(borders)를 정의하고 추가하는 일입니다. 하지만 일단 CSS의 기초에 대해 확실하게 이해만 하면 못하는 일이 거의 없게 됩니다. CSS 학습의 장점 중 하나는 잘 모르는 것에 대해서도 일단 기초만 익혀두면 무엇을 할 수 있고 무엇을 할 수 없는지를 꽤 정확하게 느낄 수 있다는 것입니다!</p> + +<h2 id="더_알아보기">더 알아보기</h2> + +<dl> + <dt><a href="/ko/docs/Web/CSS">MDN의 CSS</a></dt> + <dd>MDN의 CSS 문서 목록에 대한 주 진입 지점입니다. CSS 언어의 모든 기능에 대한 자세한 참조 문서 목록을 찾을 수 있습니다. 혹시 속성(property)이 가질 수 있는 모든 값(values)에 대한 정보가 필요한가요? 그렇다면 이곳으로 이동하세요.</dd> +</dl> diff --git a/files/ko/learn/css/introduction_to_css/기본적인_css_이해/index.html b/files/ko/learn/css/introduction_to_css/기본적인_css_이해/index.html new file mode 100644 index 0000000000..d16df40221 --- /dev/null +++ b/files/ko/learn/css/introduction_to_css/기본적인_css_이해/index.html @@ -0,0 +1,128 @@ +--- +title: 기본적인 CSS 이해 +slug: Learn/CSS/Introduction_to_CSS/기본적인_CSS_이해 +translation_of: Learn/CSS/Building_blocks/Fundamental_CSS_comprehension +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenu("Learn/CSS/Introduction_to_CSS/Debugging_CSS", "Learn/CSS/Introduction_to_CSS")}}</div> + +<p class="summary">You've covered a lot in this module, so it must feel good to have reached the end! The final step before you move on is to attempt the assessment for the module — this involves a number of related exercises that must be completed in order to create the final design — a business card/gamer card/social media profile.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Prerequisites:</th> + <td>Before attempting this assessment you should have already worked through all the articles in this module.</td> + </tr> + <tr> + <th scope="row">Objective:</th> + <td>To test comprehension of fundamental CSS theory, syntax and mechanics.</td> + </tr> + </tbody> +</table> + +<h2 id="Starting_point">Starting point</h2> + +<p>To get this assessment started, you should:</p> + +<ul> + <li>Go and grab the <a href="https://github.com/mdn/learning-area/blob/master/css/introduction-to-css/fundamental-css-comprehension/index.html">HTML file for the exercise</a>, and the <a href="https://github.com/mdn/learning-area/blob/master/css/introduction-to-css/fundamental-css-comprehension/chris.jpg">associated image file</a>, and save them in a new directory on your local computer. If you want to use your own image file and fill your own name in, you are welcome to — just make sure the image is square.</li> + <li>Grab the <a href="https://github.com/mdn/learning-area/blob/master/css/introduction-to-css/fundamental-css-comprehension/style-resources.txt">CSS resources text file</a> — this contains a set of raw selectors and rulesets that you'll need to study and combine to answer part of this assessment.</li> +</ul> + +<div class="note"> +<p><strong>Note</strong>: Alternatively, you could use a site like <a class="external external-icon" href="http://jsbin.com/">JSBin</a> or <a class="external external-icon" href="https://thimble.mozilla.org/">Thimble</a> to do your assessment. You could paste the HTML and fill in the CSS into one of these online editors, and use <a href="http://mdn.github.io/learning-area/css/introduction-to-css/fundamental-css-comprehension/chris.jpg">this URL</a> to point the <code><img></code> element to the image file. If the online editor you are using doesn't have a separate CSS panel, feel free to put it in a <code><style></code> element in the head of the document.</p> +</div> + +<h2 id="Project_brief">Project brief</h2> + +<p>You have been provided with some raw HTML and an image, and need to write the necessary CSS to style this into a nifty little online business card, which can perhaps double as a gamer card or social media profile. The following sections describe what you need to do.</p> + +<p>Basic setup:</p> + +<ul> + <li>First of all, create a new file in the same directory as your HTML and image files. Call it something really imaginative like <code>style.css</code>.</li> + <li>Link your CSS to your HTML file via a <code><link></code> element.</li> + <li>The first two rulesets in the CSS resource file are yours, for FREE! After you've finished rejoicing at your good fortune, copy and paste them into the top of your new CSS file. Use them as a test to make sure your CSS is properly applied to your HTML.</li> + <li>Above the two rules, add a CSS comment with some text inside it to indicate that this is a set of general styles for the overall page. "General page styles" would do. Also add three more comments at the bottom of the CSS file to indicate styles specific to the setup of the card container, styles specific to the header and footer, and styles specific to the main business card contents. From now on, subsequent styles added to the stylesheet should be organized in an appropriate place.</li> +</ul> + +<p>Taking care of the selectors and rulesets provided in the CSS resource file:</p> + +<ul> + <li>Next up, we'd like you to look at the four selectors, and calculate the specificity for each one. Write these down somewhere where they can be found later on, such as in a comment at the top of your CSS.</li> + <li>Now it's time to put the right selector on the right rule set! You've got four pairs of selector and ruleset to match in your CSS resources. Do this now, and add them to your CSS file. You need to: + <ul> + <li>Give the main card container a fixed width/height, solid background color, border, and border-radius (rounded corners!), amongst other things.</li> + <li>Give the header a background gradient that goes from darker to lighter, plus rounded corners that fit in with the rounded corners set on the main card container.</li> + <li>Give the footer a background gradient that goes from lighter to darker, plus rounded corners that fit in with the rounded corners set on the main card container.</li> + <li>Float the image to the right so that it sticks to the right hand side of the main business card contents, and give it a max-height of 100% (a clever trick that ensures that it will grow/shrink to stay the same height as its parent container, regardless of what height it becomes.)</li> + </ul> + </li> + <li>Beware! There are two errors in the provided rulesets. Using any technique that you know, track these down and fix them before moving on.</li> +</ul> + +<p>New rulesets you need to write:</p> + +<ul> + <li>Write a ruleset that targets both the card header, and card footer, giving them both a computed total height of 50px (including a content height of 30px and padding of 10px on all sides.) But express it in <code>em</code>s.</li> + <li>The default margin applied to the <code><h2></code> and <code><p></code> elements by the browser will interfere with our design, so write a rule that targets all these elements and sets their margin to 0.</li> + <li>To stop the image from spilling out of the main business card content (the <code><article></code> element), we need to give it a specific height. Set the <code><article></code>'s height to 120px, but expressed in <code>em</code>s. Also give it a background color of semi-transparent black, resulting in a slightly darker shade that lets the background red color shine through a bit too.</li> + <li>Write a ruleset that gives the <code><h2></code> an effective font size of 20px (but expressed in <code>em</code>s) and an appropriate line height to place it in the center of the header's content box. Recall from earlier that the content box height should be 30px — this gives you all the numbers you need to calculate the line height.</li> + <li>Write a ruleset that gives the <code><p></code> inside the footer an effective font size of 15px (but expressed in <code>em</code>s) and an appropriate line height to place it in the center of the footer's content box. Recall from earlier that the content box height should be 30px — this gives you all the numbers you need to calculate the line height.</li> + <li>As a last little touch, give the paragraph inside the <code><article></code> an appropriate padding value so that its left edge lines up with the <code><h2></code> and footer paragraph, and set its color to be fairly light so it is easy to read.</li> +</ul> + +<div class="note"> +<p><strong>Note</strong>: Bear in mind that the second ruleset sets <code>font-size: 10px;</code> on the <code><html></code> element — this means that for any descendants of <code><html></code>, an em will be equal to 10px rather than 16px as it is by default. (This is of course, provided the descendants in question don't have any ancestors sitting in between them and <code><html></code> in the hierarchy that have a different <code>font-size</code> set on them. This could affect the values you need, although in this simple example this is not an issue.)</p> +</div> + +<p>Other things to think about:</p> + +<ul> + <li>You'll get bonus marks if you write your CSS for maximum readability, with a separate declaration on each line.</li> + <li>You should include <code>.card</code> at the start of the selector chain in all your rules, so that these rules wouldn't interfere with the styling of any other elements if the business card were to be put on a page with a load of other content.</li> +</ul> + +<h2 id="Hints_and_tips">Hints and tips</h2> + +<ul> + <li>You don't need to edit the HTML in any way, except to apply the CSS to your HTML.</li> + <li>When trying to work out the <code>em</code> value you need to represent a certain pixel length, think about what base font size the root (<code><html></code>) element has, and what it needs to be multiplied by to get the desired value. That'll give you your em value, at least in a simple case like this.</li> +</ul> + +<h2 id="Example">Example</h2> + +<p>The following screenshot shows an example of what the finished design should look like:</p> + +<p><img alt="A view of the finished business card, show a reader header and footer, and a darker center panel containing the main details and image." src="https://mdn.mozillademos.org/files/12616/business-card.png" style="display: block; margin: 0 auto;"></p> + +<p> </p> + +<h2 id="Assessment">Assessment</h2> + +<p>If you are following this assessment as part of an organized course, you should be able to give your work to your teacher/mentor for marking. If you are self-learning, then you can get the marking guide fairly easily by asking on the <a href="https://discourse.mozilla.org/t/fundamental-css-comprehension-assessment/24682">discussion thread about this exercise</a>, or in the <a href="irc://irc.mozilla.org/mdn">#mdn</a> IRC channel on <a href="https://wiki.mozilla.org/IRC">Mozilla IRC</a>. Try the exercise first — there is nothing to be gained by cheating!</p> + +<p>{{PreviousMenu("Learn/CSS/Introduction_to_CSS/Debugging_CSS", "Learn/CSS/Introduction_to_CSS")}}</p> + +<p> </p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/CSS/Introduction_to_CSS/How_CSS_works">How CSS works</a></li> + <li><a href="/en-US/docs/Learn/CSS/Introduction_to_CSS/Syntax">CSS syntax</a></li> + <li><a href="/en-US/docs/Learn/CSS/Introduction_to_CSS/Selectors">Selectors</a></li> + <li><a href="/en-US/docs/Learn/CSS/Introduction_to_CSS/Selectors/Simple_selectors">Simple selectors</a></li> + <li><a href="/en-US/docs/Learn/CSS/Introduction_to_CSS/Selectors/Attribute_selectors">Attribute selectors</a></li> + <li><a href="/en-US/docs/Learn/CSS/Introduction_to_CSS/Selectors/Pseudo-classes_and_pseudo-elements">Pseudo-classes and pseudo-elements</a></li> + <li><a href="/en-US/docs/Learn/CSS/Introduction_to_CSS/Selectors/Combinators_and_multiple_selectors">Combinators and multiple selectors</a></li> + <li><a href="/en-US/docs/Learn/CSS/Introduction_to_CSS/Values_and_units">CSS values and units</a></li> + <li><a href="/en-US/docs/Learn/CSS/Introduction_to_CSS/Cascade_and_inheritance">Cascade and inheritance</a></li> + <li><a href="/en-US/docs/Learn/CSS/Introduction_to_CSS/Box_model">The box model</a></li> + <li><a href="/en-US/docs/Learn/CSS/Introduction_to_CSS/Debugging_CSS">Debugging CSS</a></li> + <li><a href="/en-US/docs/Learn/CSS/Introduction_to_CSS/Fundamental_CSS_comprehension">Fundamental CSS comprehension</a></li> +</ul> + +<p> </p> diff --git a/files/ko/learn/css/styling_text/fundamentals/index.html b/files/ko/learn/css/styling_text/fundamentals/index.html new file mode 100644 index 0000000000..64ee947683 --- /dev/null +++ b/files/ko/learn/css/styling_text/fundamentals/index.html @@ -0,0 +1,734 @@ +--- +title: 기본적인 텍스트 및 글꼴 스타일링 +slug: Learn/CSS/Styling_text/Fundamentals +translation_of: Learn/CSS/Styling_text/Fundamentals +--- +<div>{{LearnSidebar}}</div> + +<div>{{NextMenu("Learn/CSS/Styling_text/Styling_lists", "Learn/CSS/Styling_text")}}</div> + +<p class="summary"><span class="seoSummary">이 기사에서는 {{glossary("CSS")}} 를 사용하여 텍스트 스타일링을 마스터하기 위한 과정을 시작합니다.</span> 여기에서는 글꼴 굵기, 종류 및 스타일, 글꼴 약식 (shorthand), 텍스트 정렬 및 기타 효과, 줄 및 문자 간격 설정을 포함하여, 텍스트/글꼴 스타일링의 모든 기본 사항에 대해 자세히 설명합니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">전제조건</th> + <td>Basic computer literacy, HTML basics (study <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">Introduction to HTML</a>), CSS basics (study <a href="/en-US/docs/Learn/CSS/Introduction_to_CSS">Introduction to CSS</a>).</td> + </tr> + <tr> + <th scope="row">목적:</th> + <td>웹 페이지에서 텍스트 스타일을 지정하는 데 필요한 기본 속성 및 기술 습득하기.</td> + </tr> + </tbody> +</table> + +<h2 id="CSS_에서_텍스트_스타일링과_관련이_있는_것은_무엇입니까">CSS 에서 텍스트 스타일링과 관련이 있는 것은 무엇입니까?</h2> + +<p>HTML 및 CSS 를 사용한 작업에서 이미 경험한 것처럼 요소 내부의 텍스트는 요소의 내용 박스안에 배치됩니다. 콘텐츠 영역의 왼쪽 상단 (또는 RTL 언어 콘텐츠의 경우, 오른쪽 상단) 에서 시작하여 행의 끝으로 흐릅니다. 끝까지 도달하면 다음 줄로 내려가서 모든 내용이 박스에 들어갈 때까지 다음 줄로 계속 진행합니다. 텍스트 내용은 일련의 인라인 요소처럼 효과적으로 작동하며, 서로 인접한 줄에 배치되면 줄 끝에 도달할 때까지 줄 바꿈을 만들지 않거나, {{htmlelement("br")}} 요소를 사용하여 수동으로 줄 바꿈을 수행하지 않습니다.</p> + +<div class="note"> +<p><strong>참고</strong>: 위의 단락으로 인해 혼동을 느끼게 되더라도 상관없이 — go back and review our <a href="/en-US/docs/Learn/CSS/Introduction_to_CSS/Box_model">박스 모델</a> 기사를 검토하여, 박스 모델 이론을 정리하십시오.</p> +</div> + +<p>텍스트 스타일을 지정하는 데 사용되는 CSS 속성은 일반적으로 두 가지 카테고리로 분류되며, 이 기사에서는 별도로 살펴보겠습니다.properties used to style text generally fall into two categories, which we'll look at separately in this article:</p> + +<ul> + <li><strong>글꼴 스타일</strong>: 텍스트에 적용되는 글꼴에 영향을 주고, 적용되는 글꼴, 크기, 굵기, 이탤릭체 등에 영향을 주는 속성입니다.</li> + <li><strong>텍스트 레이아웃 스타일</strong>: 텍스트의 간격 및 기타 레이아웃 기능에 영향을 주는 속성으로, 예를 들어 선 과 문자 사이의 간격 및 내용 박스 내에서 텍스트가 정렬되는 방식을 조작할 수 있습니다.</li> +</ul> + +<div class="note"> +<p><strong>참고</strong>: 요소 내부의 텍스트는 모두 하나의 단일 entity 로 영향을 받습니다. 텍스트의 하위 섹션은 적절한 요소 (예: {{htmlelement("span")}} 또는 {{htmlelement("strong")}}) 으로 감싸거나, or use a text-specific pseudo-element like <a href="/en-US/docs/Web/CSS/::first-letter">::first-letter</a> (요소 텍스트의 첫 번째 문자 선택), <a href="/en-US/docs/Web/CSS/::first-line">::first-line</a> (요소 텍스트의 첫 번째 행 선택) 또는 <a href="/en-US/docs/Web/CSS/::selection">::selection</a> (커서로 현재 강조 표시된 텍스트 선택) 과 같은 텍스트 특정 pseudo-element 를 사용하십시오.</p> +</div> + +<h2 id="글꼴">글꼴</h2> + +<p>글꼴 스타일링의 속성을 살펴보도록 하겠습니다. 이 예에서는 동일한 HTML 샘플에 몇 가지 다른 CSS 속성을 적용합니다:</p> + +<pre class="brush: html"><h1>Tommy the cat</h1> + +<p>I remember as if it were a meal ago...</p> + +<p>Said Tommy the Cat as he reeled back to clear whatever foreign matter + may have nestled its way into his mighty throat. Many a fat alley rat +had met its demise while staring point blank down the cavernous barrel of + this awesome prowling machine. Truly a wonder of nature this urban +predator — Tommy the cat had many a story to tell. But it was a rare +occasion such as this that he did.</p></pre> + +<p><a href="http://mdn.github.io/learning-area/css/styling-text/fundamentals/">완성된 예제는 Github</a> 에서 찾을 수 있습니다 (<a href="https://github.com/mdn/learning-area/blob/master/css/styling-text/fundamentals/index.html">소스 코드</a> 참조.)</p> + +<h3 id="색상">색상</h3> + +<p>{{cssxref("color")}} 속성은 선택한 요소의 전경 내용의 색상을 설정합니다 (일반적으로 텍스트이지만, {{cssxref("text-decoration")}} 속성을 사용하여 텍스트에 배치되는 밑줄이나 오버라인과 같은 몇 가지 다른 것도 포함할 수 있습니다.</p> + +<p><code>color</code> 은 모든 <a href="/en-US/Learn/CSS/Introduction_to_CSS/Values_and_units#Colors">CSS 색상 단위</a> 를 사용할 수 있습니다. 예를 들면 다음과 같습니다:</p> + +<pre class="brush: css">p { + color: red; +}</pre> + +<p>이렇게하면 다음과 같이 표준 브라우저 기본값이 검은색이 아닌 빨간색으로 표시됩니다:</p> + +<div class="hidden"> +<pre class="brush: html"><h1>Tommy the cat</h1> + +<p>I remember as if it were a meal ago...</p> + +<p>Said Tommy the Cat as he reeled back to clear whatever foreign matter + may have nestled its way into his mighty throat. Many a fat alley rat +had met its demise while staring point blank down the cavernous barrel of + this awesome prowling machine. Truly a wonder of nature this urban +predator — Tommy the cat had many a story to tell. But it was a rare +occasion such as this that he did.</p></pre> +</div> + +<p>{{ EmbedLiveSample('Color', '100%', 220) }}</p> + +<h3 id="글꼴_종류">글꼴 종류</h3> + +<p>텍스트에 다른 글꼴을 설정하려면, {{cssxref("font-family")}} 속성을 사용하여 브라우저에서 선택한 요소에 적용할 글꼴 (또는 글꼴 목록) 을 지정할 수 있습니다. 브라우저는 웹 사이트에 액세스하는 컴퓨터에서 글꼴을 사용할 수 있는 경우에만 글꼴을 적용합니다; 그렇지 않으면, 브라우저 {{anch("Default fonts", "default font")}} 만 사용합니다. 간단한 예는 다음과 같습니다:</p> + +<pre class="brush: css">p { + font-family: arial; +}</pre> + +<p>이렇게하면 페이지의 모든 단락이 임의의 컴퓨터에 있는 arial 글꼴을 채택하게 됩니다.</p> + +<h4 id="웹_안전_글꼴">웹 안전 글꼴</h4> + +<p>글꼴 사용가능 여부에 대해 말하자면, 일반적으로 모든 시스템에서 사용할 수 있는 글꼴의 수는 한정되어 있으므로 큰 걱정없이 사용할 수 있습니다. 이른바 <strong>웹 안전 글꼴 </strong>입니다.</p> + +<p>대부분의 경우, 웹 개발자로서 텍스트 내용을 표시하는 데 사용되는 글꼴을 보다 구체적으로 제어하려고 합니다. 문제는 웹 페이지를 보는 데 사용되는 컴퓨터에서 어떤 글꼴을 사용할 수 있는지 알 수 있는 방법을 찾는 것입니다. 모든 경우에 이것을 알 수 있는 방법은 없지만, 웹 안전 글꼴은 가장 많이 사용되는 운영 체제 (윈도우, 맥, 가장 일반적인 리눅스 배포판, 안드로이드 및 iOS) 의 거의 모든 인스턴스에서 사용할 수 있는 것으로 알려져 있습니다.</p> + +<p>실제 웹 안전 글꼴 목록은 운영 체제가 발전함에 따라 변경될 수 있지만, 최소한 다음과 같은 웹 안전 글꼴을 고려하는 것이 좋습니다 (이중 많은 글꼴이 90 년대 후반과 2000 년대 초에 웹 initiative 를 위한 Microsoft <em><a href="https://en.wikipedia.org/wiki/Core_fonts_for_the_Web">Core 글꼴</a></em> 덕분에 많은 사람들이 대중화 되었습니다):</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">이름</th> + <th scope="col" style="white-space: nowrap;">일반 유형</th> + <th scope="col">참고</th> + </tr> + </thead> + <tbody> + <tr> + <td>Arial</td> + <td>sans-serif</td> + <td>It's often considered best practice to also add <em>Helvetica</em> as a preferred alternative to <em>Arial</em> as, although their font faces are almost identical, <em>Helvetica</em> is considered to have a nicer shape, even if <em>Arial</em> is more broadly available.</td> + </tr> + <tr> + <td>Courier New</td> + <td>monospace</td> + <td>Some OSes have an alternative (possibly older) version of the <em>Courier New</em> font called <em>Courier</em>. It's considered best practice to use both with <em>Courier New</em> as the preferred alternative.</td> + </tr> + <tr> + <td style="white-space: nowrap;">Georgia</td> + <td>serif</td> + <td></td> + </tr> + <tr> + <td style="white-space: nowrap;">Times New Roman</td> + <td>serif</td> + <td>Some OSes have an alternative (possibly older) version of the <em>Times New Roman</em> font called <em>Times</em>. It's considered best practice to use both with <em>Times New Roman</em> as the preferred alternative.</td> + </tr> + <tr> + <td>Trebuchet MS</td> + <td>sans-serif</td> + <td>You should be careful with using this font — it isn't widely available on mobile OSes.</td> + </tr> + <tr> + <td>Verdana</td> + <td>sans-serif</td> + <td></td> + </tr> + </tbody> +</table> + +<div class="note"> +<p><strong>Note</strong>: Among various resources, the <a href="http://www.cssfontstack.com/">cssfontstack.com</a> website maintains a list of web safe fonts available on Windows and macOS operating systems, which can help you make your decision about what you consider safe for your usage.</p> +</div> + +<div class="note"> +<p><strong>Note</strong>: There is a way to download a custom font along with a webpage, to allow you to customize your font usage in any way you want: <strong>web fonts</strong>. This is a little bit more complex, and we will be discussing this in a separate article later on in the module.</p> +</div> + +<h4 id="기본_글꼴">기본 글꼴</h4> + +<p>CSS 는 글꼴의 일반적인 다섯 가지 이름: <code>serif</code><font face="Open Sans, Arial, sans-serif">, </font><code>sans-serif</code>,<font face="Open Sans, Arial, sans-serif"> </font><code>monospace</code>, <code>cursive</code> 및 <code>fantasy</code> 를 정의합니다. 이러한 일반 이름을 사용할 때 사용되는 정확한 글꼴은 각 브라우저에 달려 있으며, 실행중인 운영체제에 따라 다를 수 있습니다. 브라우저가 최소한 적합한 글꼴을 제공하기 위해 최선을 다하는 최악의 시나리오를 나타나냅니다. <code>serif</code>, <code>sans-serif</code> 및 <code>monospace</code> 는 상당히 예측가능하며 합리적인 무언가를 제공해야 합니다. 반면에 , <code>cursive</code> 및 <code>fantasy</code> 는 예측하기 어렵기 때문에, 테스트할 때 신중하게 사용하는 것이 좋습니다.</p> + +<p>5 개의 이름은 다음과 같이 정의됩니다:</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">용어</th> + <th scope="col">정의</th> + <th scope="col">예제</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>serif</code></td> + <td>serifs 가 있는 글꼴 (the flourishes and other small details you see at the ends of the strokes in some typefaces)</td> + <td><span style="font-family: serif;">My big red elephant</span></td> + </tr> + <tr> + <td><code>sans-serif</code></td> + <td>serifs 가 없는 글꼴.</td> + <td><span style="font-family: sans-serif;">My big red elephant</span></td> + </tr> + <tr> + <td><code>monospace</code></td> + <td>모든 문자의 너비가 같은 글꼴로, 일반적으로 코드 목록에 사용됩니다.</td> + <td><span style="font-family: monospace;">My big red elephant</span></td> + </tr> + <tr> + <td><code>cursive</code></td> + <td>Fonts that are intended to emulate handwriting, with flowing, connected strokes.</td> + <td><span style="font-family: cursive;">My big red elephant</span></td> + </tr> + <tr> + <td><code>fantasy</code></td> + <td>장식용 글꼴.</td> + <td><span style="font-family: fantasy;">My big red elephant</span></td> + </tr> + </tbody> +</table> + +<h4 id="Font_stacks">Font stacks</h4> + +<p>웹 페이지에서 글꼴의 사용가능 여부를 보장할 수 없으므로 (어똔 이유로 웹 글꼴이 실패할 수 있음) 브라우저에서 선택할 수 있는 <strong>글꼴 스택 (font stack) </strong>을 제공할 수 있습니다. 여기에는 여러 글꼴 이름으로 구성된 <code>font-family</code> 값이 포함됩니다. 예제:</p> + +<pre class="brush: css">p { + font-family: "Trebuchet MS", Verdana, sans-serif; +}</pre> + +<p>이 경우, 브라우저는 목록 시작 부분에서 시작하여 해당 글꼴이 시스템에서 사용 가능한지 확인합니다. 이 글꼴이 있으면, 해당 글꼴이 선택한 요소에 적용됩니다. 그렇지 않으면, 다음 글꼴로 이동합니다.</p> + +<p>나열된 글꼴 중 사용 가능한 글꼴이 없는 경우, 브라우저가 최소한 대략 비슷한 것을 제공할 수 있도록 스택 끝에 적절한 일반 글꼴 이름을 제공하는 것이 좋습니다.이 점을 강조하기 위해 다른 옵션 — 일반적으로 Time New Roman — 을 사용할 수 없는 경우 단락에 기본 serif 글꼴이 제공됩니다. 이는 san-serif 글꼴에 적합하지 않습니다!</p> + +<div class="note"> +<p><strong>참고</strong>: <code>Trebuchet MS</code> 와 같이 둘 이상의 단어가 있는 글꼴 이름은 따옴표로 묶어야합니다, 예를 들면 <code>"Trebuchet MS"</code>.</p> +</div> + +<h4 id="font-family_예제">font-family 예제</h4> + +<p>단락에 sans-serif 글꼴을 제공하여 이전 예제에 추가하겠습니다:</p> + +<pre class="brush: css">p { + color: red; + font-family: Helvetica, Arial, sans-serif; +}</pre> + +<p>결과는 다음과 같습니다:</p> + +<div class="hidden"> +<pre class="brush: html"><h1>Tommy the cat</h1> + +<p>I remember as if it were a meal ago...</p> + +<p>Said Tommy the Cat as he reeled back to clear whatever foreign matter + may have nestled its way into his mighty throat. Many a fat alley rat +had met its demise while staring point blank down the cavernous barrel of + this awesome prowling machine. Truly a wonder of nature this urban +predator — Tommy the cat had many a story to tell. But it was a rare +occasion such as this that he did.</p></pre> +</div> + +<p>{{ EmbedLiveSample('A_font-family_example', '100%', 220) }}</p> + +<h3 id="글꼴_크기">글꼴 크기</h3> + +<p>In our previous module's <a href="/en-US/docs/Learn/CSS/Introduction_to_CSS/Values_and_units">CSS values and units</a> article, we reviewed <a href="/en-US/Learn/CSS/Introduction_to_CSS/Values_and_units#Length_and_size">length and size units</a>. Font size (set with the {{cssxref("font-size")}} property) can take values measured in most of these units (and others, such as <a href="/en-US/Learn/CSS/Introduction_to_CSS/Values_and_units#Percentages">percentages</a>), however the most common units you'll use to size text are:</p> + +<ul> + <li><code>px</code> (pixels): The number of pixels high you want the text to be. This is an absolute unit — it results in the same final computed value for the font on the page in pretty much any situation.</li> + <li><code>em</code>s: 1em is equal to the font size set on the parent element of the current element we are styling (more specifically, the width of a capital letter M contained inside the parent element.) This can become tricky to work out if you have a lot of nested elements with different font sizes set, but it is doable, as you'll see below. Why bother? It is quite natural once you get used to it, and you can use <code>em</code>s to size everything, not just text. You can have an entire website sized using ems, which makes maintenance easy.</li> + <li><code>rem</code>s: These work just like <code>em</code>s, except that 1<code>rem</code> is equal to the font size set on the root element of the document (i.e. {{htmlelement("html")}}), not the parent element. This makes doing the maths to work out your font sizes much easier, but unfortunately <code>rem</code>s are not supported in Internet Explorer 8 and below. If you need to support older browsers with your project, you can either stick to using <code>em</code>s or <code>px</code>, or use a {{glossary("polyfill")}} such as <a href="https://github.com/chuckcarpenter/REM-unit-polyfill">REM-unit-polyfill</a>. </li> +</ul> + +<p>The <code>font-size</code> of an element is inherited from that element's parent element. This all starts with the root element of the entire document — {{htmlelement("html")}} — the <code>font-size</code> of which is set to 16px as standard across browsers. Any paragraph (or other element that doesn't have a different size set by the browser) inside the root element will have a final size of 16px. Other elements may have different default sizes, for example an {{htmlelement("h1")}} element has a size of 2ems set by default, so will have a final size of 32px.</p> + +<p>Things become more tricky when you start altering the font size of nested elements. For example, if you had an {{htmlelement("article")}} element in your page, and set its font-size to <code>1.5em</code>s (which would compute to 24px final size), and then wanted the paragraphs inside the <code><article></code> elements to have a computed font size of 20px, what em value would you use?</p> + +<pre class="brush: html"><!-- document base font-size is 16px --> +<article> <!-- If my font-size is 1.5em --> + <p>My paragraph</p> <!-- How do I compute to 20px font-size? --> +</article></pre> + +<p>You would need to set its em value to 20/24, or <code>0.83333333em</code>s. The maths can be complicated, so you need to be careful about how you style things. It is best to use rems where you can, to keep things simple, and avoid setting the font-size of container elements where possible.</p> + +<h4 id="A_simple_sizing_example">A simple sizing example</h4> + +<p>When sizing your text, it is usually a good idea to set the base <code>font-size</code> of the document to 10px, so that then the maths is a lot easier to work out — required (r)em values are then the pixel font size divided by 10, not 16. After doing that, you can easily size the different types of text in your document to what you want. It is a good idea to list all your <code>font-size</code> rulesets in a designated area in your stylesheet, so they are easy to find.</p> + +<p>Our new result is like so:</p> + +<div class="hidden"> +<pre class="brush: html"><h1>Tommy the cat</h1> + +<p>I remember as if it were a meal ago...</p> + +<p>Said Tommy the Cat as he reeled back to clear whatever foreign matter + may have nestled its way into his mighty throat. Many a fat alley rat +had met its demise while staring point blank down the cavernous barrel of + this awesome prowling machine. Truly a wonder of nature this urban +predator — Tommy the cat had many a story to tell. But it was a rare +occasion such as this that he did.</p> +</pre> +</div> + +<pre class="brush: css">html { + font-size: 10px; +} + +h1 { + font-size: 2.6rem; +} + +p { + font-size: 1.4rem; + color: red; + font-family: Helvetica, Arial, sans-serif; +}</pre> + +<p>{{ EmbedLiveSample('A_simple_sizing_example', '100%', 220) }}</p> + +<h3 id="Font_style_font_weight_text_transform_and_text_decoration">Font style, font weight, text transform, and text decoration</h3> + +<p>CSS provides four common properties to alter the visual weight/emphasis of text:</p> + +<ul> + <li>{{cssxref("font-style")}}: Used to turn italic text on and off. Possible values are as follows (you'll rarely use this, unless you want to turn some italic styling off for some reason): + <ul> + <li><code>normal</code>: Sets the text to the normal font (turns existing italics off.)</li> + <li><code>italic</code>: Sets the text to use the <em>italic version of the font</em> if available; if not available, it will simulate italics with oblique instead.</li> + <li><code>oblique</code>: Sets the text to use a simulated version of an italic font, created by <span style="font-style: oblique;">slanting the normal version</span>.</li> + </ul> + </li> + <li>{{cssxref("font-weight")}}: Sets how bold the text is. This has many values available in case you have many font variants available (such as <em>-light</em>, <em>-normal</em>, <em>-bold</em>, <em>-extrabold</em>, <em>-black</em>, etc.), but realistically you'll rarely use any of them except for <code>normal</code> and <code>bold</code>: + <ul> + <li><code>normal</code>, <code>bold</code>: Normal and <strong style="font-weight: bold;">bold</strong> font weight</li> + <li><code>lighter</code>, <code>bolder</code>: Sets the current element's boldness to be one step lighter or heavier than its parent element's boldness.</li> + <li><code>100</code>–<code>900</code>: Numeric boldness values that provide finer grained control than the above keywords, if needed. </li> + </ul> + </li> + <li>{{cssxref("text-transform")}}: Allows you to set your font to be transformed. Values include: + <ul> + <li><code>none</code>: Prevents any transformation.</li> + <li><code>uppercase</code>: Transforms <span style="text-transform: uppercase;">all text to capitals</span>.</li> + <li><code>lowercase</code>: Transforms all text to lower case.</li> + <li><code>capitalize</code>: Transforms all words to <span style="text-transform: capitalize;">have the first letter capitalized</span>.</li> + <li><code>full-width</code>: Transforms all glyphs to be <span style="text-transform: full-width;">written inside a fixed-width square</span>, similar to a monospace font, allowing aligning of e.g. latin characters along with asian language glyphs (like Chinese, Japanese, Korean.)</li> + </ul> + </li> + <li>{{cssxref("text-decoration")}}: Sets/unsets text decorations on fonts (you'll mainly use this to unset the default underline on links when styling them.) Available values are: + <ul> + <li><code>none</code>: Unsets any text decorations already present.</li> + <li><code>underline</code>: <u>Underlines the text</u>.</li> + <li><code>overline</code>: <span style="text-decoration: overline;">Gives the text an overline</span>.</li> + <li><code>line-through</code>: Puts a <s style="text-decoration: line-through;">strikethrough over the text</s>.</li> + </ul> + You should note that {{cssxref("text-decoration")}} can accept multiple values at once, if you want to add multiple decorations simultaneously, for example <span style="text-decoration: underline overline;"><code>text-decoration: underline overline</code></span>. Also note that {{cssxref("text-decoration")}} is a shorthand property for {{cssxref("text-decoration-line")}}, {{cssxref("text-decoration-style")}}, and {{cssxref("text-decoration-color")}}. You can use combinations of these property values to create interesting effects, for example <span style="text-decoration: line-through red wavy;"><code>text-decoration: line-through red wavy</code>.</span></li> +</ul> + +<p>Let's look at adding a couple of these properties to our example:</p> + +<p>Our new result is like so:</p> + +<div class="hidden"> +<pre class="brush: html"><h1>Tommy the cat</h1> + +<p>I remember as if it were a meal ago...</p> + +<p>Said Tommy the Cat as he reeled back to clear whatever foreign matter + may have nestled its way into his mighty throat. Many a fat alley rat +had met its demise while staring point blank down the cavernous barrel of + this awesome prowling machine. Truly a wonder of nature this urban +predator — Tommy the cat had many a story to tell. But it was a rare +occasion such as this that he did.</p> +</pre> +</div> + +<pre class="brush: css">html { + font-size: 10px; +} + +h1 { + font-size: 2.6rem; + text-transform: capitalize; +} + +h1 + p { + font-weight: bold; +} + +p { + font-size: 1.4rem; + color: red; + font-family: Helvetica, Arial, sans-serif; +}</pre> + +<p>{{ EmbedLiveSample('Font_style_font_weight_text_transform_and_text_decoration', '100%', 220) }}</p> + +<h3 id="Text_drop_shadows">Text drop shadows</h3> + +<p>You can apply drop shadows to your text using the {{cssxref("text-shadow")}} property. This takes up to four values, as shown in the example below:</p> + +<pre class="brush: css">text-shadow: 4px 4px 5px red;</pre> + +<p>The four properties are as follows:</p> + +<ol> + <li>The horizontal offset of the shadow from the original text — this can take most available CSS <a href="/en-US/Learn/CSS/Introduction_to_CSS/Values_and_units#Length_and_size">length and size units</a>, but you'll most commonly use px. This value has to be included.</li> + <li>The vertical offset of the shadow from the original text; behaves basically just like the horizontal offset, except that it moves the shadow up/down, not left/right. This value has to be included.</li> + <li>The blur radius — a higher value means the shadow is dispersed more widely. If this value is not included, it defaults to 0, which means no blur. This can take most available CSS <a href="/en-US/Learn/CSS/Introduction_to_CSS/Values_and_units#Length_and_size">length and size units</a>.</li> + <li>The base color of the shadow, which can take any <a href="/en-US/Learn/CSS/Introduction_to_CSS/Values_and_units#Colors">CSS color unit</a>. If not included, it defaults to <code>black</code>.</li> +</ol> + +<div class="note"> +<p><strong>Note</strong>: Positive offset values move the shadow right and down, but you can also use negative offset values to move the shadow left and up, for example <code>-1px -1px</code>.</p> +</div> + +<h4 id="Multiple_shadows">Multiple shadows</h4> + +<p>You can apply multiple shadows to the same text by including multiple shadow values separated by commas, for example:</p> + +<pre class="brush: css"><code class="language-css"><span class="property token">text-shadow</span><span class="punctuation token">:</span> -<span class="number token">1</span>px -<span class="number token">1</span>px <span class="number token">1</span>px <span class="hexcode token">#aaa</span>, + <span class="number token">0</span>px <span class="number token">4</span>px <span class="number token">1</span>px <span class="function token">rgba</span><span class="punctuation token">(</span><span class="number token">0</span>,<span class="number token">0</span>,<span class="number token">0</span>,<span class="number token">0.5</span><span class="punctuation token">)</span>, + <span class="number token">4</span>px <span class="number token">4</span>px <span class="number token">5</span>px <span class="function token">rgba</span><span class="punctuation token">(</span><span class="number token">0</span>,<span class="number token">0</span>,<span class="number token">0</span>,<span class="number token">0.7</span><span class="punctuation token">)</span>, + <span class="number token">0</span>px <span class="number token">0</span>px <span class="number token">7</span>px <span class="function token">rgba</span><span class="punctuation token">(</span><span class="number token">0</span>,<span class="number token">0</span>,<span class="number token">0</span>,<span class="number token">0.4</span><span class="punctuation token">)</span><span class="punctuation token">;</span></code></pre> + +<p>If we applied this to the {{htmlelement("h1")}} element in our Tommy the cat example, we'd end up with this:</p> + +<div class="hidden"> +<pre class="brush: html"><h1>Tommy the cat</h1> + +<p>I remember as if it were a meal ago...</p> + +<p>Said Tommy the Cat as he reeled back to clear whatever foreign matter + may have nestled its way into his mighty throat. Many a fat alley rat +had met its demise while staring point blank down the cavernous barrel of + this awesome prowling machine. Truly a wonder of nature this urban +predator — Tommy the cat had many a story to tell. But it was a rare +occasion such as this that he did.</p> +</pre> + +<pre class="brush: css">html { + font-size: 10px; +} + +h1 { + font-size: 26px; + text-transform: capitalize; + text-shadow: -1px -1px 1px #aaa, + 0px 2px 1px rgba(0,0,0,0.5), + 2px 2px 2px rgba(0,0,0,0.7), + 0px 0px 3px rgba(0,0,0,0.4); +} + +h1 + p { + font-weight: bold; +} + +p { + font-size: 14px; + color: red; + font-family: Helvetica, Arial, sans-serif; +}</pre> +</div> + +<p>{{ EmbedLiveSample('Multiple_shadows', '100%', 220) }}</p> + +<div class="note"> +<p><strong>Note</strong>: You can see more interesting examples of <code>text-shadow</code> usage in the Sitepoint article <a href="http://www.sitepoint.com/moonlighting-css-text-shadow/">Moonlighting with CSS text-shadow</a>.</p> +</div> + +<h2 id="텍스트_레이아웃">텍스트 레이아웃</h2> + +<p>With basic font properties out the way, let's now have a look at properties we can use to affect text layout.</p> + +<h3 id="텍스트_정렬">텍스트 정렬</h3> + +<p>The {{cssxref("text-align")}} property is used to control how text is aligned within its containing content box. The available values are as follows, and work in pretty much the same way as they do in a regular word processor application:</p> + +<ul> + <li><code>left</code>: Left justifies the text.</li> + <li><code>right</code>: Right justifies the text.</li> + <li><code>center</code>: Centers the text.</li> + <li><code>justify</code>: Makes the text spread out, varying the gaps in between the words so that all lines of text are the same width. You need to use this carefully — it can look terrible, especially when applied to a paragraph with lots of long words in it. If you are going to use this, you should also think about using something else along with it, such as {{cssxref("hyphens")}}, to break some of the longer words across lines.</li> +</ul> + +<p>If we applied <code>text-align: center;</code> to the {{htmlelement("h1")}} in our example, we'd end up with this:</p> + +<div class="hidden"> +<pre class="brush: html"><h1>Tommy the cat</h1> + +<p>I remember as if it were a meal ago...</p> + +<p>Said Tommy the Cat as he reeled back to clear whatever foreign matter + may have nestled its way into his mighty throat. Many a fat alley rat +had met its demise while staring point blank down the cavernous barrel of + this awesome prowling machine. Truly a wonder of nature this urban +predator — Tommy the cat had many a story to tell. But it was a rare +occasion such as this that he did.</p> +</pre> + +<pre class="brush: css">html { + font-size: 10px; +} + +h1 { + font-size: 2.6rem; + text-transform: capitalize; + text-shadow: -1px -1px 1px #aaa, + 0px 2px 1px rgba(0,0,0,0.5), + 2px 2px 2px rgba(0,0,0,0.7), + 0px 0px 3px rgba(0,0,0,0.4); + text-align: center; +} + +h1 + p { + font-weight: bold; +} + +p { + font-size: 1.4rem; + color: red; + font-family: Helvetica, Arial, sans-serif; +}</pre> +</div> + +<p>{{ EmbedLiveSample('Text_alignment', '100%', 220) }}</p> + +<h3 id="Line_height">Line height</h3> + +<p>The {{cssxref("line-height")}} property sets the height of each line of text — this can take most <a href="/en-US/Learn/CSS/Introduction_to_CSS/Values_and_units#Length_and_size">length and size units</a>, but can also take a unitless value, which acts as a multiplier and is generally considered the best option — the {{cssxref("font-size")}} is multiplied to get the <code>line-height</code>. Body text generally looks nicer and is easier to read when the lines are spaced apart; the recommended line height is around 1.5–2 (double spaced.) So to set our lines of text to 1.5 times the height of the font, you'd use this:</p> + +<pre class="brush: css">line-height: 1.5;</pre> + +<p>Applying this to the {{htmlelement("p")}} elements in our example would give us this result:</p> + +<div class="hidden"> +<pre class="brush: html"><h1>Tommy the cat</h1> + +<p>I remember as if it were a meal ago...</p> + +<p>Said Tommy the Cat as he reeled back to clear whatever foreign matter + may have nestled its way into his mighty throat. Many a fat alley rat +had met its demise while staring point blank down the cavernous barrel of + this awesome prowling machine. Truly a wonder of nature this urban +predator — Tommy the cat had many a story to tell. But it was a rare +occasion such as this that he did.</p> +</pre> + +<pre class="brush: css">html { + font-size: 10px; +} + +h1 { + font-size: 2.6rem; + text-transform: capitalize; + text-shadow: -1px -1px 1px #aaa, + 0px 2px 1px rgba(0,0,0,0.5), + 2px 2px 2px rgba(0,0,0,0.7), + 0px 0px 3px rgba(0,0,0,0.4); + text-align: center; +} + +h1 + p { + font-weight: bold; +} + +p { + font-size: 1.4rem; + color: red; + font-family: Helvetica, Arial, sans-serif; + line-height: 1.5; +}</pre> +</div> + +<p>{{ EmbedLiveSample('Line_height', '100%', 250) }}</p> + +<h3 id="Letter_and_word_spacing">Letter and word spacing</h3> + +<p>The {{cssxref("letter-spacing")}} and {{cssxref("word-spacing")}} properties allow you to set the spacing between letters and words in your text. You won't use these very often, but might find a use for them to get a certain look, or to improve the legibility of a particularly dense font. They can take most <a href="/en-US/Learn/CSS/Introduction_to_CSS/Values_and_units#Length_and_size">length and size units</a>.</p> + +<p>So as an example, if we applied the following to the first line of the {{htmlelement("p")}} elements in our example:</p> + +<pre class="brush: css">p::first-line { + letter-spacing: 2px; + word-spacing: 4px; +}</pre> + +<p>We'd get the following:</p> + +<div class="hidden"> +<pre class="brush: html"><h1>Tommy the cat</h1> + +<p>I remember as if it were a meal ago...</p> + +<p>Said Tommy the Cat as he reeled back to clear whatever foreign matter + may have nestled its way into his mighty throat. Many a fat alley rat +had met its demise while staring point blank down the cavernous barrel of + this awesome prowling machine. Truly a wonder of nature this urban +predator — Tommy the cat had many a story to tell. But it was a rare +occasion such as this that he did.</p> +</pre> + +<pre class="brush: css">html { + font-size: 10px; +} + +h1 { + font-size: 2.6rem; + text-transform: capitalize; + text-shadow: -1px -1px 1px #aaa, + 0px 2px 1px rgba(0,0,0,0.5), + 2px 2px 2px rgba(0,0,0,0.7), + 0px 0px 3px rgba(0,0,0,0.4); + text-align: center; +} + +h1 + p { + font-weight: bold; +} + +p::first-line { + letter-spacing: 2px; + word-spacing: 4px; +} + +p { + font-size: 1.4rem; + color: red; + font-family: Helvetica, Arial, sans-serif; + line-height: 1.5; +}</pre> +</div> + +<p>{{ EmbedLiveSample('Letter_and_word_spacing', '100%', 250) }}</p> + +<h3 id="볼_가치가_있는_다른_속성들">볼 가치가 있는 다른 속성들</h3> + +<p>The above properties give you an idea of how to start styling text on a webpage, but there are many more properties you could use. We just wanted to cover the most important ones here. Once you've become used to using the above, you should also explore the following:</p> + +<p>Font styles:</p> + +<ul> + <li>{{cssxref("font-variant")}}: Switch between small caps and normal font alternatives.</li> + <li>{{cssxref("font-kerning")}}: Switch font kerning options on and off.</li> + <li>{{cssxref("font-feature-settings")}}: Switch various <a href="https://en.wikipedia.org/wiki/OpenType">OpenType</a> font features on and off.</li> + <li>{{cssxref("font-variant-alternates")}}: Control the use of alternate glyphs for a given font-face.</li> + <li>{{cssxref("font-variant-caps")}}: Control the use of alternate capital glyphs.</li> + <li>{{cssxref("font-variant-east-asian")}}: Control the usage of alternate glyphs for East Asian scripts, like Japanese and Chinese.</li> + <li>{{cssxref("font-variant-ligatures")}}: Control which ligatures and contextual forms are used in text.</li> + <li>{{cssxref("font-variant-numeric")}}: Control the usage of alternate glyphs for numbers, fractions, and ordinal markers.</li> + <li>{{cssxref("font-variant-position")}}: Control the usage of alternate glyphs of smaller sizes positioned as superscript or subscript.</li> + <li>{{cssxref("font-size-adjust")}}: Adjust the visual size of the font independently of its actual font size.</li> + <li>{{cssxref("font-stretch")}}: Switch between possible alternative stretched versions of a given font.</li> + <li>{{cssxref("text-underline-position")}}: Specify the position of underlines set using the <code>text-decoration-line</code> property <code>underline</code> value.</li> + <li>{{cssxref("text-rendering")}}: Try to perform some text rendering optimization.</li> +</ul> + +<p>Text layout styles</p> + +<ul> + <li>{{cssxref("text-indent")}}: Specify how much horizontal space should be left before the beginning of the first line of the text content.</li> + <li>{{cssxref("text-overflow")}}: Define how overflowed content that is not displayed is signaled to users.</li> + <li>{{cssxref("white-space")}}: Define how whitespace and associated line breaks inside the element are handled.</li> + <li>{{cssxref("word-break")}}: Specify whether to break lines within words.</li> + <li>{{cssxref("direction")}}: Define the text direction (This depends on the language and usually it's better to let HTML handle that part as it is tied to the text content.)</li> + <li>{{cssxref("hyphens")}}: Switch on and off hyphenation for supported languages.</li> + <li>{{cssxref("line-break")}}: Relax or strengthen line breaking for Asian languages.</li> + <li>{{cssxref("text-align-last")}}: Define how the last line of a block or a line, right before a forced line break, is aligned.</li> + <li>{{cssxref("text-orientation")}}: Define the orientation of the text in a line.</li> + <li>{{cssxref("word-wrap")}}: Specify whether or not the browser may break lines within words in order to prevent overflow.</li> + <li>{{cssxref("writing-mode")}}: Define whether lines of text are laid out horizontally or vertically and the direction in which subsequent lines flow.</li> +</ul> + +<h2 id="글꼴_약식_shorthand">글꼴 약식 (shorthand)</h2> + +<p>Many font properties can also be set through the shorthand property {{cssxref("font")}}. These are written in the following order: {{cssxref("font-style")}}, {{cssxref("font-variant")}}, {{cssxref("font-weight")}}, {{cssxref("font-stretch")}}, {{cssxref("font-size")}}, {{cssxref("line-height")}}, and {{cssxref("font-family")}}.</p> + +<p>Among all those properties, only <code>font-size</code> and <code>font-family</code> are required when using the <code>font</code> shorthand property.</p> + +<p>A forward slash has to be put in between the {{cssxref("font-size")}} and {{cssxref("line-height")}} properties.</p> + +<p>A full example would look like this:</p> + +<pre class="brush: css">font: italic normal bold normal 3em/1.5 Helvetica, Arial, sans-serif;</pre> + +<h2 id="Active_learning_Playing_with_styling_text">Active learning: Playing with styling text</h2> + +<p>In this active learning session, we don't have any specific exercises for you to do: we'd just like you to have a good play with some font/text layout properties, and see what you can produce! You can either do this using offline HTML/CSS files, or enter your code into the live editable example below.</p> + +<p>If you make a mistake, you can always reset it using the <em>Reset</em> button.</p> + +<div class="hidden"> +<h6 id="Playable_code">Playable code</h6> + +<pre class="brush: html"><div class="body-wrapper" style="font-family: 'Open Sans Light',Helvetica,Arial,sans-serif;"> + <h2>HTML Input</h2> + <textarea id="code" class="html-input" style="width: 90%;height: 10em;padding: 10px;border: 1px solid #0095dd;"> + <p>Some sample text for your delight</p></textarea> + + <h2>CSS Input</h2> + <textarea id="code" class="css-input" style="width: 90%;height: 10em;padding: 10px;border: 1px solid #0095dd;">p { + + }</textarea> + + <h2>Output</h2> + <div class="output" style="width: 90%;height: 10em;padding: 10px;border: 1px solid #0095dd;"></div> + <div class="controls"> + <input id="reset" type="button" value="Reset" style="margin: 10px 10px 0 0;"> + </div> +</div> +</pre> + +<pre class="brush: js">var htmlInput = document.querySelector(".html-input"); +var cssInput = document.querySelector(".css-input"); +var reset = document.getElementById("reset"); +var htmlCode = htmlInput.value; +var cssCode = cssInput.value; +var output = document.querySelector(".output"); + +var styleElem = document.createElement('style'); +var headElem = document.querySelector('head'); +headElem.appendChild(styleElem); + +function drawOutput() { + output.innerHTML = htmlInput.value; + styleElem.textContent = cssInput.value; +} + +reset.addEventListener("click", function() { + htmlInput.value = htmlCode; + cssInput.value = cssCode; + drawOutput(); +}); + +htmlInput.addEventListener("input", drawOutput); +cssInput.addEventListener("input", drawOutput); +window.addEventListener("load", drawOutput); +</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code', 700, 800) }}</p> + +<h2 id="Summary">Summary</h2> + +<p>We hoped you enjoyed playing with text in this article! The next article will give you all you need to know about styling HTML lists.</p> + +<p>{{NextMenu("Learn/CSS/Styling_text/Styling_lists", "Learn/CSS/Styling_text")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/CSS/Styling_text/Fundamentals">Fundamental text and font styling</a></li> + <li><a href="/en-US/docs/Learn/CSS/Styling_text/Styling_lists">Styling lists</a></li> + <li><a href="/en-US/docs/Learn/CSS/Styling_text/Styling_links">Styling links</a></li> + <li><a href="/en-US/docs/Learn/CSS/Styling_text/Web_fonts">Web fonts</a></li> + <li><a href="/en-US/Learn/CSS/Styling_text/Typesetting_a_homepage">Typesetting a community school homepage</a></li> +</ul> diff --git a/files/ko/learn/css/styling_text/index.html b/files/ko/learn/css/styling_text/index.html new file mode 100644 index 0000000000..1a5f780b9a --- /dev/null +++ b/files/ko/learn/css/styling_text/index.html @@ -0,0 +1,48 @@ +--- +title: 텍스트 스타일링 +slug: Learn/CSS/Styling_text +tags: + - CSS + - 그림자 + - 리스트 + - 모듈 + - 웹 폰트 + - 초보자 + - 폰트 +translation_of: Learn/CSS/Styling_text +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">CSS 기초가 어느 정도 완성되었다면, 여러분이 집중해야 할 다음 CSS 주제는 CSS로 가장 흔하게 할 것 중 하나인 텍스트를 꾸며주는 것입니다. 우리는 글꼴 과 볼드체, 이탤릭체, 줄 띄어쓰기, 단어 띄어쓰기, 그림자 넣기 등과 같은 텍스트 기능을 설정하는 것을 포함한 텍스트 스타일링의 기초를 배웁니다. 여러분의 페이지에 사용자 정의 글꼴을 설정하고 리스트와 링크를 꾸며줌으로써 이 강의를 끝마칩니다. </p> + +<h2 id="전제_조건">전제 조건</h2> + +<p>이 강의를 시작하기 전에, <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">HTML 소개</a> 에서 설명한대로 이미 HTML 에 대해 잘 알고 있어야하며, <a href="/en-US/docs/Learn/CSS/Introduction_to_CSS">CSS 소개</a> 에서 설명한대로 CSS 기본 사항에 익숙해야합니다.</p> + +<div class="note"> +<p><strong>참고</strong>: 자신의 파일을 만들 수 없는 컴퓨터/태블릿/기타 장치에서 작업하는 경우, <a href="http://jsbin.com/">JSBin</a>,<a href="https://codepen.io/"> CodePen</a> 또는 <a href="https://thimble.mozilla.org/">Thimble</a> 와 같은 온라인 코딩 프로그램에서 대부분의 코드 예제를 시험해 볼 수 있습니다.</p> +</div> + +<h2 id="안내">안내</h2> + +<p>이 강의에는 다음 기사가 포함되어 있으며, HTML 텍스트 콘텐츠를 스타일링하는 데 필요한 모든 기본 사항을 알려줍니다.</p> + +<dl> + <dt><a href="/en-US/docs/Learn/CSS/Styling_text/Fundamentals">기본적인 텍스트 및 글꼴 스타일</a></dt> + <dd>이 기사에서는 글꼴 굵기, 종류 및 스타일 설정, 글꼴 약식 (shorthand), 텍스트 정렬 및 기타 효과, 줄 및 문자 간격 설정을 포함하여 텍스트/글꼴 스타일의 모든 기본 사항을 자세히 설명합니다.</dd> + <dt><a href="/en-US/docs/Learn/CSS/Styling_text/Styling_lists">목록 스타일링</a></dt> + <dd>목록은 대부분 다른 텍스트처럼 작동하지만, 알아야 할 목록과 관련된 몇 가지 CSS 속성과 고려해야 할 모범 사례가 있습니다. 이 기사는 모든 것을 설명합니다.</dd> + <dt><a href="/en-US/docs/Learn/CSS/Styling_text/Styling_links">링크 스타일링</a></dt> + <dd>링크를 스타일링 할 때, pseudo-classes 를 사용하여 링크 상태를 효과적으로 스타일링하는 방법과 네비게이션 메뉴 및 탭과 같은 일반적인 다양한 인터페이스 기능을 사용하기 위해 링크를 스타일링하는 방법을 이해하는 것이 중요합니다. 이 기사에서는 이러한 모든 주제를 살펴볼 것입니다.</dd> + <dt><a href="/en-US/docs/Learn/CSS/Styling_text/Web_fonts">웹 글꼴</a></dt> + <dd>여기에서는 웹 글꼴을 자세하게 살펴볼 것입니다 — 웹 글꼴과 함께 사용자 정의 글꼴을 다운로드하여, 보다 다양한 사용자 정의 텍스트 스타일을 지정할 수 있습니다.</dd> +</dl> + +<h2 id="평가">평가</h2> + +<p>다음 평가는 위의 안내에서 다루는 텍스트 스타일링 기술에 대한 이해를 테스트합니다.</p> + +<dl> + <dt><a href="/en-US/Learn/CSS/Styling_text/Typesetting_a_homepage">커뮤니티 스쿨 홈페이지 typesetting</a></dt> + <dd>이 평가에서는 커뮤니티 스툴 홈페이지의 텍스트 스타일을 지정함으로써 스타일 텍스트에 대한 이해를 테스트합니다.</dd> +</dl> diff --git a/files/ko/learn/css/styling_text/styling_lists/index.html b/files/ko/learn/css/styling_text/styling_lists/index.html new file mode 100644 index 0000000000..843636c554 --- /dev/null +++ b/files/ko/learn/css/styling_text/styling_lists/index.html @@ -0,0 +1,389 @@ +--- +title: 목록 스타일링 +slug: Learn/CSS/Styling_text/Styling_lists +translation_of: Learn/CSS/Styling_text/Styling_lists +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/CSS/Styling_text/Fundamentals", "Learn/CSS/Styling_text/Styling_links", "Learn/CSS/Styling_text")}}</div> + +<p class="summary"><a href="/en-US/Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals#Lists">목록</a> 은 대부분 다른 텍스트처럼 작동하지만, 알아야 할 목록과 관련된 몇 가지 CSS 속성과 고려해야 할 모범 사례가 있습니다. 이 기사는 모든 것을 설명합니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">전제조건:</th> + <td>Basic computer literacy, HTML basics (study <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">Introduction to HTML</a>), CSS basics (study <a href="/en-US/docs/Learn/CSS/Introduction_to_CSS">Introduction to CSS</a>), <a href="/en-US/docs/Learn/CSS/Styling_text/Fundamentals">CSS text and font fundamentals</a>.</td> + </tr> + <tr> + <th scope="row">목적:</th> + <td>목록 스타일과 관련된 모범 사례 및 속성에 익숙해지기.</td> + </tr> + </tbody> +</table> + +<h2 id="간단한_목록_예제">간단한 목록 예제</h2> + +<p>우선, 간단한 목록 예제를 봅시다. 이 기사 전체에서 우리는 순서가 없는, 순서가 있는, 설명 목록을 살펴볼 것입니다 — 모두 유사한 스타일링 기능이 있으며, 일부 유형은 목록 유형과 다릅니다. 스타일이 지정되지 않은 예제는 <a href="http://mdn.github.io/learning-area/css/styling-text/styling-lists/unstyled-list.html">Github 에서 가능</a> 합니다 (<a href="https://github.com/mdn/learning-area/blob/master/css/styling-text/styling-lists/unstyled-list.html">소스 코드</a> 도 확인하십시오.)</p> + +<p>목록 예제의 HTML 은 다음과 같습니다:</p> + +<pre class="brush: html"><h2>Shopping (unordered) list</h2> + +<p>Paragraph for reference, paragraph for reference, paragraph for reference, +paragraph for reference, paragraph for reference, paragraph for reference.</p> + +<ul> + <li>Hummus</li> + <li>Pita</li> + <li>Green salad</li> + <li>Halloumi</li> +</ul> + +<h2>Recipe (ordered) list</h2> + +<p>Paragraph for reference, paragraph for reference, paragraph for reference, +paragraph for reference, paragraph for reference, paragraph for reference.</p> + +<ol> + <li>Toast pita, leave to cool, then slice down the edge.</li> + <li>Fry the halloumi in a shallow, non-stick pan, until browned on both sides.</li> + <li>Wash and chop the salad.</li> + <li>Fill pita with salad, hummus, and fried halloumi.</li> +</ol> + +<h2>Ingredient description list</h2> + +<p>Paragraph for reference, paragraph for reference, paragraph for reference, +paragraph for reference, paragraph for reference, paragraph for reference.</p> + +<dl> + <dt>Hummus</dt> + <dd>A thick dip/sauce generally made from chick peas blended with tahini, lemon juice, salt, garlic, and other ingredients.</dd> + <dt>Pita</dt> + <dd>A soft, slightly leavened flatbread.</dd> + <dt>Halloumi</dt> + <dd>A semi-hard, unripened, brined cheese with a higher-than-usual melting point, usually made from goat/sheep milk.</dd> + <dt>Green salad</dt> + <dd>That green healthy stuff that many of us just use to garnish kebabs.</dd> +</dl></pre> + +<p>If you go to the live example now and investigate the list elements using <a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">browser developer tools</a>, you'll notice a couple of styling defaults:</p> + +<ul> + <li>The {{htmlelement("ul")}} and {{htmlelement("ol")}} elements have a top and bottom {{cssxref("margin")}} of <code>16px</code> (<code>1em</code>) and a {{cssxref("padding-left")}} of <code>40px</code> (<code>2.5em</code>.)</li> + <li>The list items ({{htmlelement("li")}} elements) have no set defaults for spacing.</li> + <li>The {{htmlelement("dl")}} element has a top and bottom {{cssxref("margin")}} of <code>16px</code> (<code>1em</code>), but no padding set.</li> + <li>The {{htmlelement("dd")}} elements have {{cssxref("margin-left")}} of <code>40px</code> (<code>2.5em</code>.)</li> + <li>The {{htmlelement("p")}} elements we've included for reference have a top and bottom {{cssxref("margin")}} of <code>16px</code> (<code>1em</code>), the same as the different list types.</li> +</ul> + +<h2 id="Handling_list_spacing">Handling list spacing</h2> + +<p>When styling lists, you need to adjust their styles so they keep the same vertical spacing as their surrounding elements (such as paragraphs and images; sometimes called vertical rhythm), and the same horizontal spacing as each other (you can see the <a href="http://mdn.github.io/learning-area/css/styling-text/styling-lists/">finished styled example</a> on Github, and <a href="https://github.com/mdn/learning-area/blob/master/css/styling-text/styling-lists/index.html">find the source code</a> too.)</p> + +<p>The CSS used for the text styling and spacing is as follows:</p> + +<pre class="brush: css">/* General styles */ + +html { + font-family: Helvetica, Arial, sans-serif; + font-size: 10px; +} + +h2 { + font-size: 2rem; +} + +ul,ol,dl,p { + font-size: 1.5rem; +} + +li, p { + line-height: 1.5; +} + +/* Description list styles */ + + +dd, dt { + line-height: 1.5; +} + +dt { + font-weight: bold; +} + +dd { + margin-bottom: 1.5rem; +}</pre> + +<ul> + <li>The first rule sets a sitewide font and a baseline font size of 10px. These are inherited by everything on the page.</li> + <li>Rules 2 and 3 set relative font sizes for the headings, different list types (the children of the list elements inherit these), and paragraphs. This means that each paragraph and list will have the same font size and top and bottom spacing, helping to keep the vertical rhythm consistent.</li> + <li>Rule 4 sets the same {{cssxref("line-height")}} on the paragraphs and list items — so the paragraphs and each individual list item will have the same spacing between lines. This will also help to keep the vertical rhythm consistent.</li> + <li>Rules 5 and 6 apply to the description list — we set the same <code>line-height</code> on the description list terms and descriptions as we did with the paragraphs and list items. Again, consistency is good! We also make the description terms have bold font, so they visually stand out easier.<span id="cke_bm_126E" style="display: none;"> </span></li> +</ul> + +<h2 id="List-specific_styles">List-specific styles</h2> + +<p>Now we've looked at general spacing techniques for lists, let's explore some list-specific properties. There are three properties you should know about to start with, which can be set on {{htmlelement("ul")}} or {{htmlelement("ol")}} elements:</p> + +<ul> + <li>{{cssxref("list-style-type")}}: Sets the type of bullets to use for the list, for example, square or circle bullets for an unordered list, or numbers, letters or roman numerals for an ordered list.</li> + <li>{{cssxref("list-style-position")}}: Sets whether the bullets appear inside the list items, or outside them before the start of each item.</li> + <li>{{cssxref("list-style-image")}}: Allows you to use a custom image for the bullet, rather than a simple square or circle.</li> +</ul> + +<h3 id="Bullet_styles">Bullet styles</h3> + +<p>As mentioned above, the {{cssxref("list-style-type")}} property allows you to set what type of bullet to use for the bullet points. In our example, we've set the ordered list to use uppercase roman numerals, with:</p> + +<pre class="brush: css">ol { + list-style-type: upper-roman; +}</pre> + +<p>This gives us the following look:</p> + +<p><img alt="an ordered list with the bullet points set to appear outside the list item text." src="https://mdn.mozillademos.org/files/12962/outer-bullets.png" style="border-style: solid; border-width: 1px; display: block; height: 119px; margin: 0px auto; width: 376px;"></p> + +<p>You can find a lot more options by checking out the {{cssxref("list-style-type")}} reference page.</p> + +<h3 id="Bullet_position">Bullet position</h3> + +<p>The {{cssxref("list-style-position")}} property sets whether the bullets appear inside the list items, or outside them before the start of each item. The default value is <code>outside</code>, which causes the bullets to sit outside the list items, as seen above.</p> + +<p>If you set the value to <code>inside</code>, the bullets will sit inside the lines:</p> + +<pre class="brush: css">ol { + list-style-type: upper-roman; + list-style-position: inside; +}</pre> + +<p><img alt="an ordered list with the bullet points set to appear inside the list item text." src="https://mdn.mozillademos.org/files/12958/inner-bullets.png" style="border-style: solid; border-width: 1px; display: block; height: 123px; margin: 0px auto; width: 370px;"></p> + +<h3 id="Using_a_custom_bullet_image">Using a custom bullet image</h3> + +<p>The {{cssxref("list-style-image")}} property allows you to use a custom image for your bullet. The syntax is pretty simple:</p> + +<pre class="brush: css">ul { + list-style-image: url(star.svg); +}</pre> + +<p>However, this property is a bit limited in terms of controlling the position, size, etc. of the bullets. You are better off using the {{cssxref("background")}} family of properties, which you'll learn a lot more about in the <a href="/en-US/docs/Learn/CSS/Styling_boxes">Styling boxes</a> module. For now, here's a taster!</p> + +<p>In our finished example, we have styled the unordered list like so (on top of what you've already seen above):</p> + +<pre class="brush: css">ul { + padding-left: 2rem; + list-style-type: none; +} + +ul li { + padding-left: 2rem; + background-image: url(star.svg); + background-position: 0 0; + background-size: 1.6rem 1.6rem; + background-repeat: no-repeat; +}</pre> + +<p>Here we've done the following:</p> + +<ul> + <li>Set the {{cssxref("padding-left")}} of the {{htmlelement("ul")}} down from the default <code>40px</code> to <code>20px</code>, then set the same amount on the list items. This is so that overall the list items are still lined up with the order list items and the description list descriptions, but the list items have some padding for the background images to sit inside. If we didn't do this, the background images would overlap with the list item text, which would look messy.</li> + <li>Set the {{cssxref("list-style-type")}} to <code>none</code>, so that no bullet appears by default. We're going to use {{cssxref("background")}} properties to handle the bullets instead.</li> + <li>Inserted a bullet onto each unordered list item. The relevant properties are as follows: + <ul> + <li>{{cssxref("background-image")}}: This references the path to the image file you want to use as the bullet.</li> + <li>{{cssxref("background-position")}}: This defines where in the background of the selected element the image will appear — in this case we are saying <code>0 0</code>, which means the bullet will appear in the very top left of each list item.</li> + <li>{{cssxref("background-size")}}: This sets the size of the background image. We ideally want the bullets to be the same size as the list items (or very slightly smaller or larger). We are using a size of <code>1.6rem</code> (<code>16px</code>), which fits very nicely with the <code>20px</code> padding we've allowed for the bullet to sit inside — 16px plus 4px of space between the bullet and the list item text works well.</li> + <li>{{cssxref("background-repeat")}}: By default, background images repeat until they fill up the available background space. We only want one copy of the image inserted in each case, so we set this to a value of <code>no-repeat</code>.</li> + </ul> + </li> +</ul> + +<p>This gives us the following result:</p> + +<p><img alt="an unordered list with the bullet points set as little star images" src="https://mdn.mozillademos.org/files/16226/list_formatting.png" style="border-style: solid; border-width: 1px; display: block; height: 106px; margin: 0px auto; width: 124px;"></p> + +<h3 id="list-style_shorthand">list-style shorthand</h3> + +<p>The three properties mentioned above can all be set using a single shorthand property, {{cssxref("list-style")}}. For example, the following CSS:</p> + +<pre class="brush: css">ul { + list-style-type: square; + list-style-image: url(example.png); + list-style-position: inside; +}</pre> + +<p>Could be replaced by this:</p> + +<pre class="brush: css">ul { + list-style: square url(example.png) inside; +}</pre> + +<p>The values can be listed in any order, and you can use one, two or all three (the default values used for the properties that are not included are <code>disc</code>, <code>none</code>, and <code>outside</code>). If both a <code>type</code> and an <code>image</code> are specified, the type is used as a fallback if the image can't be loaded for some reason.</p> + +<h2 id="Controlling_list_counting">Controlling list counting</h2> + +<p>Sometimes you might want to count differently on an ordered list — e.g. starting from a number other than 1, or counting backwards, or counting in steps of more than 1. HTML and CSS have some tools to help you here.</p> + +<h3 id="start">start</h3> + +<p>The {{htmlattrxref("start","ol")}} attribute allows you to start the list counting from a number other than 1. The following example:</p> + +<pre class="brush: html"><ol start="4"> + <li>Toast pita, leave to cool, then slice down the edge.</li> + <li>Fry the halloumi in a shallow, non-stick pan, until browned on both sides.</li> + <li>Wash and chop the salad.</li> + <li>Fill pita with salad, hummus, and fried halloumi.</li> +</ol></pre> + +<p>Gives you this output:</p> + +<p>{{ EmbedLiveSample('start', '100%', 150) }}</p> + +<h3 id="reversed">reversed</h3> + +<p>The {{htmlattrxref("reversed","ol")}} attribute will start the list counting down instead of up. The following example:</p> + +<pre class="brush: html"><ol start="4" reversed> + <li>Toast pita, leave to cool, then slice down the edge.</li> + <li>Fry the halloumi in a shallow, non-stick pan, until browned on both sides.</li> + <li>Wash and chop the salad.</li> + <li>Fill pita with salad, hummus, and fried halloumi.</li> +</ol></pre> + +<p>Gives you this output:</p> + +<p>{{ EmbedLiveSample('reversed', '100%', 150) }}</p> + +<div class="note"> +<p><strong>Note</strong>: If there are more list items in a reversed list than the value of the <code>start</code> attribute, the count will continue to zero and then into negative values. </p> +</div> + +<h3 id="value">value</h3> + +<p>The {{htmlattrxref("value","ol")}} attribute allows you to set your list items to specific numerical values. The following example:</p> + +<pre class="brush: html"><ol> + <li value="2">Toast pita, leave to cool, then slice down the edge.</li> + <li value="4">Fry the halloumi in a shallow, non-stick pan, until browned on both sides.</li> + <li value="6">Wash and chop the salad.</li> + <li value="8">Fill pita with salad, hummus, and fried halloumi.</li> +</ol></pre> + +<p>Gives you this output:</p> + +<p>{{ EmbedLiveSample('value', '100%', 150) }}</p> + +<div class="note"> +<p><strong>Note</strong>: Even if you are using a non-number {{cssxref("list-style-type")}}, you still need to use the equivalent numerical values in the <code>value</code> attribute.</p> +</div> + +<h2 id="Active_learning_Styling_a_nested_list">Active learning: Styling a nested list</h2> + +<p>In this active learning session, we want you to take what you've learned above and have a go at styling a nested list. We've provided you with the HTML, and we want you to:</p> + +<ol> + <li>Give the unordered list square bullets.</li> + <li>Give the unordered list items and the ordered list items a line height of 1.5 of their font-size.</li> + <li>Give the ordered list lower alphabetical bullets.</li> + <li>Feel free to play with the list example as much as you like, experimenting with bullet types, spacing, or whatever else you can find.</li> +</ol> + +<p>If you make a mistake, you can always reset it using the <em>Reset</em> button. If you get really stuck, press the <em>Show solution</em> button to see a potential answer.</p> + +<div class="hidden"> +<h6 id="Playable_code">Playable code</h6> + +<pre class="brush: html"><div class="body-wrapper" style="font-family: 'Open Sans Light',Helvetica,Arial,sans-serif;"> + <h2>HTML Input</h2> + <textarea id="code" class="html-input" style="width: 90%;height: 10em;padding: 10px;border: 1px solid #0095dd;"><ul> + <li>First, light the candle.</li> + <li>Next, open the box.</li> + <li>Finally, place the three magic items in the box, in this exact order, to complete the spell: + <ol> + <li>The book of spells</li> + <li>The shiny rod</li> + <li>The goblin statue</li> + </ol> + </li> +</ul></textarea> + + <h2>CSS Input</h2> + <textarea id="code" class="css-input" style="width: 90%;height: 10em;padding: 10px;border: 1px solid #0095dd;"></textarea> + + <h2>Output</h2> + <div class="output" style="width: 90%;height: 12em;padding: 10px;border: 1px solid #0095dd;overflow: auto;"></div> + <div class="controls"> + <input id="reset" type="button" value="Reset" style="margin: 10px 10px 0 0;"> + <input id="solution" type="button" value="Show solution" style="margin: 10px 0 0 10px;"> + </div> +</div> +</pre> + +<pre class="brush: js">var htmlInput = document.querySelector(".html-input"); +var cssInput = document.querySelector(".css-input"); +var reset = document.getElementById("reset"); +var htmlCode = htmlInput.value; +var cssCode = cssInput.value; +var output = document.querySelector(".output"); +var solution = document.getElementById("solution"); + +var styleElem = document.createElement('style'); +var headElem = document.querySelector('head'); +headElem.appendChild(styleElem); + +function drawOutput() { + output.innerHTML = htmlInput.value; + styleElem.textContent = cssInput.value; +} + +reset.addEventListener("click", function() { + htmlInput.value = htmlCode; + cssInput.value = cssCode; + drawOutput(); +}); + +solution.addEventListener("click", function() { + htmlInput.value = htmlCode; + cssInput.value = 'ul {\n list-style-type: square;\n}\n\nul li, ol li {\n line-height: 1.5;\n}\n\nol {\n list-style-type: lower-alpha\n}'; + drawOutput(); +}); + +htmlInput.addEventListener("input", drawOutput); +cssInput.addEventListener("input", drawOutput); +window.addEventListener("load", drawOutput); +</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code', 700, 800) }}</p> + +<h2 id="See_also">See also</h2> + +<p>CSS counters provide advanced tools for customizing list counting and styling, but they are quite complex. We recommend looking into these if you want to stretch yourself. See:</p> + +<ul> + <li>{{cssxref("@counter-style")}}</li> + <li>{{cssxref("counter-increment")}}</li> + <li>{{cssxref("counter-reset")}}</li> +</ul> + +<h2 id="Summary">Summary</h2> + +<p>Lists are relatively easy to get the hang of styling once you know a few associated basic principles and specific properties. In the next article we'll get on to link styling techniques.</p> + +<p>{{PreviousMenuNext("Learn/CSS/Styling_text/Fundamentals", "Learn/CSS/Styling_text/Styling_links", "Learn/CSS/Styling_text")}}</p> + + + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/CSS/Styling_text/Fundamentals">Fundamental text and font styling</a></li> + <li><a href="/en-US/docs/Learn/CSS/Styling_text/Styling_lists">Styling lists</a></li> + <li><a href="/en-US/docs/Learn/CSS/Styling_text/Styling_links">Styling links</a></li> + <li><a href="/en-US/docs/Learn/CSS/Styling_text/Web_fonts">Web fonts</a></li> + <li><a href="/en-US/Learn/CSS/Styling_text/Typesetting_a_homepage">Typesetting a community school homepage</a></li> +</ul> diff --git a/files/ko/learn/front-end_web_developer/index.html b/files/ko/learn/front-end_web_developer/index.html new file mode 100644 index 0000000000..0d0ae72a9b --- /dev/null +++ b/files/ko/learn/front-end_web_developer/index.html @@ -0,0 +1,194 @@ +--- +title: Front-end web developer +slug: Learn/Front-end_web_developer +translation_of: Learn/Front-end_web_developer +--- +<p>{{learnsidebar}}</p> + +<p>프론트 개발자가 되는 과정에 오신 것을 환영합니다!</p> + +<p>여기에서는 프론트 엔드 웹 개발자가 되기 위해 알아야 할 모든 것을 배울수 있는 체계적인 강좌를 제공합니다. 각 섹션을 통해 학습하면서 새로운 기술을 배우거나 기존 기술을 개선하세요. 각 섹션에는 진행하기 전에 잘 이해하고 있는지 확인하기 위한 연습 및 평가가 포함되어 있습니다.</p> + +<h2 id="다루는_주제">다루는 주제</h2> + +<p>다루는 내용은 다음과 같습니다.</p> + +<ul> + <li>기본 설정 및 학습 방법에 대한 학습</li> + <li>웹 표준 및 모범 사례(예: 접근성 및 브라우저간 호환성)</li> + <li>웹 구조와 의미를 제공하는 언어인 HTML</li> + <li>웹 페이지 스타일을 지정하는 언어인 CSS</li> + <li>웹에서 동적인 기능을 만드는데 사용되는 스크립트 언어인 JavaScript</li> + <li>최신 클라이언트 웹 개발을 용이하게 해주는 도구</li> +</ul> + +<p>섹션을 순서대로 살펴볼 수 있지만, 각 섹션은 독립적입니다. 예를들어 이미 HTML을 알고 있는 경우 CSS 섹션으로 건너뛸 수 있습니다.</p> + +<h2 id="전제_조건">전제 조건</h2> + +<p>이 강좌를 시작하기 위한 사전 지식은 필요하지 않습니다. 최신 웹 브라우저를 실행할 수 있는 컴퓨터, 인터넷 연결, 학습 의지만 있으면 됩니다.</p> + +<p>프론트 엔드 웹 개발이 자신에게 적합한지 확실하지 않거나, 더 길고 완전한 과정을 시작하기 전에 부드러운 소개를 원하면 먼저 <a href="/ko/docs/Learn/Getting_started_with_the_web">웹과 함께 시작하기</a> 를 읽어보세요.</p> + +<h2 id="도움말_얻기">도움말 얻기</h2> + +<p>우리는 가능한 한 편안하게 프론트 엔드 웹 개발을 학습할 수 있도록 노력했습니다. 그러나 무언가를 이해하지 못하거나 일부 코드가 작동하지 않아 학습을 멈추게 될 수 있습니다.</p> + +<p>당황하지 마세요. 우리는 초보자든 전문 웹 개발자든 모두 어떤 문제에 막혀 있습니다. <a href="/ko/docs/Learn/Learning_and_getting_help">학습 및 도움말 얻기</a> 문서는 정보를 찾고 도움을 줄 수 있는 일련의 팁을 제공합니다. 그래도 문제가 해결되지 않는다면 <a href="https://discourse.mozilla.org/c/mdn/learn/">Discourse forum</a>에 문제를 게시하세요.</p> + +<p>시작합시다. 행운을 빌어요!</p> + +<h2 id="학습_과정">학습 과정</h2> + +<h3 id="시작하기">시작하기</h3> + +<p>완료 시간: 1.5–2 시간</p> + +<h4 id="전제_조건_2">전제 조건</h4> + +<p>기본적인 컴퓨터 사용 능력 외에는 아무것도 없습니다.</p> + +<h4 id="앞으로_나아갈_준비가_되었는지_어떻게_알_수_있나요">앞으로 나아갈 준비가 되었는지 어떻게 알 수 있나요?</h4> + +<p>이 강좌에는 평가가 없습니다. 그러나 건너뛰지 마세요. 강좌의 후반부에 있는 연습문제를 준비하는것도 중요합니다.</p> + +<h4 id="가이드">가이드</h4> + +<ul> + <li><a href="/ko/docs/Learn/Getting_started_with_the_web/Installing_basic_software">기본 소프트웨어 설치하기</a>— 기본 도구 설정 (15 분 읽기)</li> + <li><a href="/ko/docs/Learn/Getting_started_with_the_web/The_web_and_web_standards">웹과 웹 표준에 대한 배경</a> (45 분 읽기)</li> + <li><a href="/ko/docs/Learn/Learning_and_getting_help">학습과 도움말 얻기</a> (45 분 읽기)</li> +</ul> + +<h3 id="HTML을_사용한_의미론과_구조">HTML을 사용한 의미론과 구조</h3> + +<p>완료 시간: 35–50 시간</p> + +<h4 id="전제_조건_3">전제 조건</h4> + +<p>기본적인 컴퓨터 활용 능력과 기본적인 웹 개발 환경 외에는 아무것도 없습니다.</p> + +<h4 id="앞으로_나아갈_준비가_되었는지_어떻게_알_수_있나요_2">앞으로 나아갈 준비가 되었는지 어떻게 알 수 있나요?</h4> + +<p>각 모듈(교과목 단위)의 평가는 주제에 대한 지식을 테스트하도록 설계되었습니다.<br> + 평가를 완료하면 다음 모듈로 이동할 준비가 된 것입니다.</p> + +<h4 id="모듈">모듈</h4> + +<ul> + <li><a href="/ko/docs/Learn/HTML/Introduction_to_HTML">HTML 소개</a> (15–20 시간 읽기/평가)</li> + <li><a href="/ko/docs/Learn/HTML/Multimedia_and_embedding">Multimedia 와 embedding</a> (15–20 시간 읽기/학습)</li> + <li><a href="/ko/docs/Learn/HTML/Tables">HTML tables</a> (5–10 시간 읽기/학습)</li> +</ul> + +<h3 id="CSS를_사용한_스타일링_및_레이아웃">CSS를 사용한 스타일링 및 레이아웃</h3> + +<p>완료 시간: 90–120 시간</p> + +<h4 id="전제조건">전제조건</h4> + +<p>CSS를 배우기 전에 기본적인 HTML 지식을 갖고 있는 것이 좋습니다. 최소한 <a href="/ko/docs/Learn/HTML/Introduction_to_HTML">HTML 소개</a> 를 먼저 공부해야 합니다.</p> + +<h4 id="앞으로_나아갈_준비가_되었는지_어떻게_알_수_있나요_3">앞으로 나아갈 준비가 되었는지 어떻게 알 수 있나요?</h4> + +<p>각 모듈의 평가는 주제에 대한 지식을 테스트하도록 설계되었습니다.<br> + 평가를 완료하면 다음 모듈로 이동할 준비가 된 것입니다.</p> + +<h4 id="모듈_2">모듈</h4> + +<ul> + <li><a href="/ko/docs/Learn/CSS/First_steps">CSS 첫 번째 단계</a> (10–15 시간 읽기/학습)</li> + <li><a href="/ko/docs/Learn/CSS/Building_blocks">CSS 구성 블록</a> (35–45 시간 읽기/학습)</li> + <li><a href="/ko/docs/Learn/CSS/Styling_text">텍스트 스타일링</a> (15–20 시간 읽기/학습)</li> + <li><a href="/ko/docs/Learn/CSS/CSS_layout">CSS 레이아웃</a> (30–40 시간 읽기/학습)</li> +</ul> + +<h4 id="추가_자료">추가 자료</h4> + +<ul> + <li><a href="/ko/docs/Web/CSS/Layout_cookbook">CSS 레이아웃 쿡북</a></li> +</ul> + +<h3 id="JavaScript와의_상호작용">JavaScript와의 상호작용</h3> + +<p>완료 시간: 135–185 시간</p> + +<h4 id="전제_조건_4">전제 조건</h4> + +<p>Javascript를 배우기 전에 기본적인 HTML 지식을 갖고 있는 것이 좋습니다. 최소한 <a href="/ko/docs/Learn/HTML/Introduction_to_HTML">HTML 소개</a> 를 먼저 공부해야 합니다.</p> + +<h4 id="앞으로_나아갈_준비가_되었는지_어떻게_알_수_있나요_4">앞으로 나아갈 준비가 되었는지 어떻게 알 수 있나요?</h4> + +<p>각 모듈의 평가는 주제에 대한 지식을 테스트하도록 설계되었습니다.<br> + 평가를 완료하면 다음 모듈로 이동할 준비가 된 것입니다.</p> + +<h4 id="모듈_3">모듈</h4> + +<ul> + <li><a href="/ko/docs/Learn/JavaScript/First_steps">JavaScript 첫걸음</a> (30–40 시간 읽기/평가)</li> + <li><a href="/ko/docs/Learn/JavaScript/Building_blocks">JavaScript 구성 요소</a> (25–35 시간 읽기/평가)</li> + <li><a href="/ko/docs/Learn/JavaScript/Objects">JavaScript 객체 소개</a> (25–35 시간 읽기/평가)</li> + <li><a href="/ko/docs/Learn/JavaScript/Client-side_web_APIs">Client-side web APIs</a> (30–40 시간 읽기/평가)</li> + <li><a href="/ko/docs/Learn/JavaScript/Asynchronous">비동기 JavaScript</a> (25–35 시간 읽기/평가)</li> +</ul> + +<h3 id="웹_폼_—_유저_데이터_작업">웹 폼 — 유저 데이터 작업</h3> + +<p>완료 시간: 40–50 시간</p> + +<h4 id="전제_조건_5">전제 조건</h4> + +<p>Form에는 HTML, CSS, and JavaScript 지식이 필요합니다. Form 작업의 복잡성을 감안할 때 자주 접하는 내용입니다.</p> + +<h4 id="앞으로_나아갈_준비가_되었는지_어떻게_알_수_있나요_5">앞으로 나아갈 준비가 되었는지 어떻게 알 수 있나요?</h4> + +<p>각 모듈의 평가는 주제에 대한 지식을 테스트하도록 설계되었습니다.<br> + 평가를 완료하면 다음 모듈로 이동할 준비가 된 것입니다.</p> + +<h4 id="모듈_4">모듈</h4> + +<ul> + <li><a href="/ko/docs/Learn/Forms">HTML 폼 가이드</a>(40–50 시간)</li> +</ul> + +<h3 id="모두를_위한_웹_작동_시키기">모두를 위한 웹 작동 시키기</h3> + +<p>완료 시간: 60–75 시간</p> + +<h4 id="전제_조건_6">전제 조건</h4> + +<p>이 섹션을 진행하기 전에 HTML, CSS, JavaScript를 아는 것이 좋습니다. 많은 기술과 모범 사례(best practices)가 여러 기술에 적용됩니다.</p> + +<h4 id="앞으로_나아갈_준비가_되었는지_어떻게_알_수_있나요_6">앞으로 나아갈 준비가 되었는지 어떻게 알 수 있나요?</h4> + +<p>각 모듈의 평가는 주제에 대한 지식을 테스트하도록 설계되었습니다.<br> + 평가를 완료하면 다음 모듈로 이동할 준비가 된 것입니다.</p> + +<h4 id="모듈_5">모듈</h4> + +<ul> + <li><a href="/ko/docs/Learn/Tools_and_testing/Cross_browser_testing">크로스 브라우저 테스팅</a> (25–30 시간 읽기/평가)</li> + <li><a href="/ko/docs/Learn/Accessibility">접근성</a> (20–25 시간 읽기/평가)</li> +</ul> + +<h3 id="최신_도구">최신 도구</h3> + +<p>완료 시간: 55–90 시간</p> + +<h4 id="전제_조건_7">전제 조건</h4> + +<p>이 섹션을 진행하기 전에 HTML, CSS, JavaScript를 아는 것이 좋습니다. 논의하는 도구들은 이러한 많은 기술과 함께 작동합니다.</p> + +<h4 id="앞으로_나아갈_준비가_되었는지_어떻게_알_수_있나요_7">앞으로 나아갈 준비가 되었는지 어떻게 알 수 있나요?</h4> + +<p>이 모듈에는 특정 평가가 없습니다. 두 번째, 세 번째 모듈의 끝에 있는 사례 연구 자습서는 최신 도구의 필수 요소를 파악할 수 있도록 준비했습니다.</p> + +<h4 id="모듈_6">모듈</h4> + +<ul> + <li><a href="/ko/docs/Learn/Tools_and_testing/GitHub">Git 과 GitHub</a> (5 hour read)</li> + <li><a href="/ko/docs/Learn/Tools_and_testing/Understanding_client-side_tools">클라이언트 웹 개발 도구 이해하기</a> (20–25 hour read)</li> + <li> + <p><a href="/ko/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks">Javascript 클라이언트 프레임워크 이해하기</a> (30-60 hour read/exercises)</p> + </li> +</ul> diff --git a/files/ko/learn/getting_started_with_the_web/css_기본/index.html b/files/ko/learn/getting_started_with_the_web/css_기본/index.html new file mode 100644 index 0000000000..a5e8e08648 --- /dev/null +++ b/files/ko/learn/getting_started_with_the_web/css_기본/index.html @@ -0,0 +1,293 @@ +--- +title: CSS 기초 +slug: Learn/Getting_started_with_the_web/CSS_기본 +tags: + - CSS + - 'l10n:priority' + - 꾸미기 + - 스크립트 코딩 + - 웹 + - 초보자 + - 학습 +translation_of: Learn/Getting_started_with_the_web/CSS_basics +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Getting_started_with_the_web/HTML_basics", "Learn/Getting_started_with_the_web/JavaScript_basics", "Learn/Getting_started_with_the_web")}}</div> + +<div class="summary"> +<p>CSS (Cascading Style Sheets)는 웹페이지를 꾸미려고 작성하는 코드입니다. <em>CSS 기초 </em>에서 여러분이 처음 시작하며 필요한 내용을 익히도록 도와드립니다. 저희는 다음과 같은 질문에 관한 답을 드리겠습니다. 어떻게 하면 글자색을 검정이나 빨갛게 할 수 있을까? 어떻게 하면 콘텐츠를 화면의 이런 저런 곳에 보이게 할 수 있을까? 어떻게 하면 배경 이미지와 색상들로 웹페이지를 꾸밀 수 있을까?</p> +</div> + +<h2 id="그래서_CSS가_뭔가요">그래서 CSS가 뭔가요?</h2> + +<p>HTML와 같이 CSS는 실제로 프로그래밍 언어는 아닙니다. <em>마크업(markup) 언어 </em>도 아닙니다. <em>Style sheet 언어 </em>입니다. HTML 문서에 있는 요소들에 선택적으로 스타일을 적용할 수 있다는 말입니다. 예를 들면, HTML 페이지에서 <strong>모든</strong> 문단 요소들을 선택하고 그 문단 요소들 안에 있는 텍스트를 빨갛게 바꾸려고 한다면 다음과 같이 CSS를 작성할 것입니다.</p> + +<pre class="brush: css">p { + color: red; +}</pre> + +<p>한 번 해봅시다. 텍스트 에디터의 새 파일에 위의 CSS 3줄을 복사해 붙여넣으세요. 그다음에 <code>styles</code> 디렉토리에 <code>style.css</code>로 파일을 저장하세요.</p> + +<p>아직 여러분의 HTML 문서에 CSS를 적용하는 것이 남아 있습니다. 그렇지 않으면 CSS 스타일은 그 HTML 문서가 브라우저에 표시될 때 아무 영향도 주지 않을 것입니다. (여러분이 우리 프로젝트를 따라오지 않으셨다면, <a href="/en-US/Learn/Getting_started_with_the_web/Dealing_with_files">파일 다루기</a>와 <a href="/ko/Learn/Getting_started_with_the_web/HTML_basics">HTML 기본</a>을 읽고 무엇이 먼저 필요한지를 알아보시기 바랍니다.)</p> + +<ol> + <li><code>index.html</code> 파일을 열고 head의 안쪽 어딘가(즉, <code><head></code>와 <code></head></code> 태그 사이)에 아래의 코드를 붙여 넣으세요: + + <pre class="brush: html"><link href="styles/style.css" rel="stylesheet" type="text/css"></pre> + </li> + <li><code>index.html</code>을 저장하고 브라우저에서 불러오세요. 여러분은 다음과 같은 것을 보게 되실겁니다:</li> +</ol> + +<p><img alt="A mozilla logo and some paragraphs. The paragraph text has been styled red by our css." src="https://mdn.mozillademos.org/files/9435/website-screenshot-styled.png" style="display: block; height: 832px; margin: 0px auto; width: 711px;">문단의 글자가 빨간색이라면 축하드립니다! 지금 여러분은 첫번째 CSS 를 성공적으로 작성하셨습니다!</p> + +<h3 id="CSS의_ruleset_해부">CSS의 ruleset 해부</h3> + +<p>위의 CSS를 좀 더 자세히 살펴 봅시다:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/9461/css-declaration-small.png" style="display: block; height: 480px; margin: 0px auto; width: 850px;"></p> + +<p>전체 구조는 <strong>rule set </strong>라 불립니다 (하지만 종종 줄여서 "rule"이라고 합니다). 각 부분의 이름에도 주목하세요:</p> + +<dl> + <dt>선택자(selector)</dt> + <dd>rule set의 맨 앞에 있는 HTML 요소 이름. 이것은 꾸밀 요소(들)을 선택합니다 (이 예에서는 p 요소). 다른 요소를 꾸미기 위해서는 선택자만 바꿔주세요.</dd> + <dt>선언</dt> + <dd><code>color: red</code>와 같은 단일 규칙; 여러분이 꾸미기 원하는 요소의 속성을 명시합니다.</dd> + <dt>속성(property)</dt> + <dd>주어진 HTML 요소를 꾸밀 수 있는 방법입니다. (이 예에서, <code>color</code>는 p 요소의 속성입니다.) CSS에서, rule 내에서 영향을 줄 속성을 선택합니다.</dd> + <dt>속성 값</dt> + <dd>속성의 오른쪽에, 콜론 뒤에, 주어진 속성을 위한 많은 가능한 결과중 하나를 선택하기 위해 속성 값을 갖습니다 (<code>color</code> 의 값에는 <code>red</code> 외에 많은 것이 있습니다).</dd> +</dl> + +<p>구문의 다른 중요한 부분들도 주목하세요:</p> + +<ul> + <li>각각의 rule set (셀렉터로 구분) 은 반드시 (<code>{}</code>) 로 감싸져야 합니다.</li> + <li>각각의 선언 안에, 각 속성을 해당 값과 구분하기 위해 콜론 (:)을 사용해야만 합니다.</li> + <li>각각의 rule set 안에, 각 선언을 그 다음 선언으로부터 구분하기 위해 세미콜론 (;)을 사용해야만 합니다.</li> +</ul> + +<p>그러니까 여러 속성 값들을 한번에 수정하기 위해서는, 세미콜론으로 구분해서 작성해야 합니다, 이렇게요:</p> + +<pre class="brush: css">p { + color: red; + width: 500px; + border: 1px solid black; +}</pre> + +<h3 id="여러_요소_선택하기">여러 요소 선택하기</h3> + +<p>여러분은 요소의 여러 타입을 선택하고 모두에게 하나의 rule set 을 적용할 수도 있습니다. 여러 선택자는 콤마로 구분합니다. 예를 들면:</p> + +<pre class="brush: css">p,li,h1 { + color: red; +}</pre> + +<h3 id="선택자의_여러_종류">선택자의 여러 종류</h3> + +<p>선택자는 여러 종류가 있습니다. 위에서, 우리는 주어진 HTML 문서안에 주어진 타입의 모든 요소를 선택하는 <strong>요소 선택자</strong>만 보았습니다. 하지만 이것보다 더 구체적인 선택을 만들 수 있습니다. 이것은 선택자의 일반적인 종류들입니다:</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">선택자 이름</th> + <th scope="col">선택하는 것</th> + <th scope="col">예시</th> + </tr> + </thead> + <tbody> + <tr> + <td>요소 선택자 (때때로 태그 또는 타입 선택자라 불림)</td> + <td>특정 타입의 모든 HTML 요소.</td> + <td><code>p</code><br> + <code><p> 를 선택</code></td> + </tr> + <tr> + <td>아이디 선택자</td> + <td>특정 아이디를 가진 페이지의 요소 (주어진 HTML 페이지에서, 아이디당 딱 하나의 요소만 허용됩니다).</td> + <td><code>#my-id</code><br> + <code><p id="my-id"></code> 또는 <code><a id="my-id"></code> 를 선택</td> + </tr> + <tr> + <td>클래스 선택자</td> + <td>특정 클래스를 가진 페이지의 요소 (한 페이지에 클래스가 여러번 나타날 수 있습니다).</td> + <td><code>.my-class</code><br> + <code><p class="my-class"></code> 와 <code><a class="my-class"></code> 를 선택</td> + </tr> + <tr> + <td>속성 선택자</td> + <td>특정 속성을 갖는 페이지의 요소.</td> + <td><code>img[src]</code><br> + <code><img src="myimage.png"></code> 를 선택하지만 <code><img> </code> 는 선택 안함</td> + </tr> + <tr> + <td>수도(Pseudo) 클래스 선택자</td> + <td>특정 요소이지만 특정 상태에 있을 때만, 예를 들면, hover over 상태일 때.</td> + <td><code>a:hover</code><br> + <code><a></code> 를 선택하지만, 마우스 포인터가 링크위에 있을 때만 선택함</td> + </tr> + </tbody> +</table> + +<p>탐구할 더 많은 선택자가 있습니다. 더 자세한 목록은 <a href="/en-US/docs/Web/Guide/CSS/Getting_started/Selectors">선택자 가이드</a>에서 찾아보세요.</p> + +<h2 id="글꼴과_문자">글꼴과 문자</h2> + +<p>지금까지 약간의 CSS 기본에 대해 살펴보았습니다, 우리의 예제가 멋있게 보이도록 <code>style.css</code> 파일에 더 많은 rule 과 정보를 추가해 봅시다. 우선, 글꼴과 문자가 조금 더 나아보이도록 해보죠.</p> + +<div class="note"> +<p><strong>노트</strong>: "px" 가 무슨 뜻인지 설명하는 주석을 추가해 두었습니다. CSS 문서의 /* 와 */ 사이에 있는 것은 브라우저가 코드를 표현할 때 무시하는 <strong>CSS 주석</strong>입니다. 여러분이 하고 있는 것에 대한 유용한 메모를 작성하기 위한 공간입니다.</p> +</div> + +<ol> + <li>먼저, 돌아가서 여러분이 안전한 어딘가에 저장해 두었던 <a href="/ko/docs/Learn/Getting_started_with_the_web/What_should_your_web_site_be_like#Font">구글 글꼴의 결과물</a>을 찾으세요. <code>index.html</code> 의 head 안 어딘가에 <code><link></code> 요소를 추가하세요 (다시 말해서, <code><head></code> 와 <code></head></code> 태그 사이 어디에나). 이런식이 될 겁니다: + + <pre class="brush: html"><link href='http://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'></pre> + </li> + <li>다음으로, <code>style.css</code> 파일에 이미 존재하는 rule 을 지우세요. 좋은 테스트였지만, 빨간색의 글자가 정말 좋아 보이지는 않습니다.</li> + <li>아래의 코드를 해당 위치에 추가하고, 구글 폰트로부터 얻은 <code>font-family</code> 코드를 placeholder 줄에 덮어쓰세요. (<code>font-family</code> 는 여러분이 글자를 위해 사용하길 원하는 글꼴을 의미합니다.) 이 rule 은 먼저 전체 페이지의 글자 크기와 기본 글꼴을 설정합니다. (<code>html</code>이 전체 페이지의 부모 요소일 때, 이 안의 모든 요소는 같은 <code>font-size</code> 와 <code>font-family</code> 를 물려 받습니다): + <pre class="brush: css">html { + font-size: 10px; /* px 은 'pixels' 를 의미합니다: 기본 글자 크기는 현재 10 pixels 높이입니다. */ + font-family: placeholder: 구글 폰트로부터 여러분이 얻은 마지막 결과가 있어야합니다. +}</pre> + </li> + <li>이제 HTML body 안에 문자를 포함하는 요소 <code>h1</code>, <code>li</code> 및 <code>p</code> 를 위해 글자 크기를 설정할 것입니다. 또한 조금 더 읽기 좋게 하기 위해 body 콘텐츠의 제목을 가운데 정렬하고 줄의 높이(line-height)와 자간(lettet-spacing)도 설정할 것입니다: + <pre class="brush: css">h1 { + font-size: 60px; + text-align: center; +} + +p, li { + font-size: 16px; + line-height: 2; + letter-spacing: 1px; +}</pre> + </li> +</ol> + +<p><code>px(픽셀)</code> 값들은 여러분이 원하는대로 조정할 수 있지만, 여러분이 원하는 디자인을 얻도록, 여러분의 디자인은 이런식으로 보여야 합니다:</p> + +<p><img alt="a mozilla logo and some paragraphs. a sans-serif font has been set, the font sizes, line height and letter spacing are adjusted, and the main page heading has been centered" src="https://mdn.mozillademos.org/files/9447/website-screenshot-font-small.png" style="display: block; height: 1020px; margin: 0px auto; width: 921px;"></p> + +<h2 id="박스_박스_박스의_모든_것">박스, 박스, 박스의 모든 것</h2> + +<p>CSS 작성에서 여러분이 알게 될 한 가지는 많은 것들이 박스에 관한 것이라는 겁니다 — 그들의 크기, 색상, 위치 등을 설정하는 것. 여러분의 페이지에 있는 대부분의 HTML 요소들은 서로의 위에 놓여있는 박스로 생각해볼 수 있습니다.</p> + +<p><img alt="a big stack of boxes or crates sat on top of one another" src="https://mdn.mozillademos.org/files/9441/boxes.jpg" style="display: block; height: 463px; margin: 0px auto; width: 640px;"></p> + +<p>놀랍지 않게도, CSS 레이아웃은 <em>박스모델 </em>을 주 기반으로 하고 있습니다. 여러분의 페이지의 공간을 차지하고 있는 각각의 블록들은 이와 같은 속성들을 가집니다:</p> + +<ul> + <li><code>padding</code>, 컨텐트 주위의 공간 (예, 문단 글자의 주위)</li> + <li><code>border</code>, padding 의 바깥쪽에 놓인 실선</li> + <li><code>margin</code>, 요소의 바깥쪽을 둘러싼 공간</li> +</ul> + +<p><img alt="three boxes sat inside one another. From outside to in they are labelled margin, border and padding" src="https://mdn.mozillademos.org/files/9443/box-model.png" style="display: block; height: 450px; margin: 0px auto; width: 574px;"></p> + +<p>여기서 이런 것도 사용합니다:</p> + +<ul> + <li><code>width</code> (한 요소의 너비)</li> + <li><code>background-color</code>, 요소의 콘텐츠와 padding 의 배경 색</li> + <li><code>color</code>, 한 요소의 콘텐츠 색 (일반적으로 글자색)</li> + <li><code>text-shadow</code>: 한 요소 안의 글자에 그림자를 적용</li> + <li><code>display</code>: 요소의 표시 형식을 설정합니다 (이것에 대해선 아직 걱정하지마세요)</li> +</ul> + +<p>그럼, 우리의 페이지에 더 많은 CSS를 추가해봅시다! 페이지의 아래에 이러한 새로운 rule 을 계속 추가하세요, 그리고 값을 바꾸는 실험을 통해 이것이 어떤 결과가 나타나는지 보는것을 두려워하지 마세요.</p> + +<h3 id="페이지_색_바꾸기">페이지 색 바꾸기</h3> + +<pre class="brush: css">html { + background-color: #00539F; +}</pre> + +<p>이 rule 은 전체 페이지를 위한 배경색을 설정합니다. 위의 색상 코드를 <a href="/en-US/Learn/Getting_started_with_the_web/What_should_your_web_site_be_like#Theme_color">여러분의 사이트를 계획할 때 선택했던</a> 색으로 변경하세요.</p> + +<h3 id="body_외부_정렬하기">body 외부 정렬하기</h3> + +<pre class="brush: css">body { + width: 600px; + margin: 0 auto; + background-color: #FF9500; + padding: 0 20px 20px 20px; + border: 5px solid black; +}</pre> + +<p>이제는 body 요소를 위한 것입니다. 여기 적지 않은 선언들이 있습니다. 하나 하나 모두 살펴 봅시다:</p> + +<ul> + <li><code>width: 600px;</code> — 이것은 body가 항상 600 pixels 의 너비를 갖도록 강제합니다.</li> + <li><code>margin: 0 auto;</code> — 여러분이 <code>margin</code> 또는 <code>padding</code> 처럼 한 속성에 두개의 값을 설정할 때, 첫 번째 값은 요소의 상단과 하단 (이 예시에서는 0입니다) 에 영향을 주고, 두 번째 값은 좌측 <strong>과 </strong>우측 (여기서, <code>auto</code> 는 가능한 수평공간의 왼쪽과 오른쪽을 같게 나눠주는 특별한 값입니다) 에 영향을 줍니다. 여러분은 또한 하나, 셋, 또는 네개의 값을 사용할 수도 있습니다. <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/margin#Values">여기</a>에 문서화 되어 있습니다.</li> + <li><code>background-color: #FF9500;</code> — 전과 같이, 이것은 요소의 배경색을 설정합니다. <code>html</code> 요소를 위한 짙은 파란색에 반대되도록 body 에는 붉은 빛을 띄는 오렌지색 같은 것을 사용했었습니다. 한번 시험해보세요. 흰색이나 여러분이 원하는 어떤 색이든 편하게 사용해보세요.</li> + <li><code>padding: 0 20px 20px 20px;</code> — padding 에는 콘텐츠의 주위에 약간의 공간을 주기 위한 네 개의 값이 있습니다. 이번엔 body의 상단에 no padding, 그리고 왼쪽, 아래 그리고 오른쪽에 20 pixels 을 설정하고 있습니다. 상단, 우측, 하단, 좌측 순서로 값을 설정합니다.(12시부터 시계방향)</li> + <li><code>border: 5px solid black;</code> — 이것은 간단하게 body 모든 면의 border 를 5 pixels 두깨의 실선으로 설정합니다.</li> +</ul> + +<h3 id="메인_페이지_제목_배치하고_꾸미기">메인 페이지 제목 배치하고 꾸미기</h3> + +<pre class="brush: css">h1 { + margin: 0; + padding: 20px 0; + color: #00539F; + text-shadow: 3px 3px 1px black; +}</pre> + +<p>여러분은 바디의 상단에 끔찍한 틈이 있다는 것을 알아차리셨을 겁니다. 브라우저가 <code>h1</code> 요소에 (다른 것들 사이에서) 어떤 <strong>초기 스타일링</strong>을 적용하기 때문에 발생합니다, 심지어 여러분이 아무런 CSS 를 적용하지 않았을 때도요! 안좋은 아이디어로 들릴수도 있지만, 우리는 꾸며지지 않은 웹사이트일지라도 기본적인 가독성을 갖기를 원합니다. <code>margin: 0;</code>.설정에 의해 초기 스타일링을 덮어쓰는 것으로 그 틈을 제거할 수 있습니다.</p> + +<p>다음으로, 제목의 상단과 하단 padding 을 20 pixels로 설정하고, 제목 글자 색을 html 배경색과 같게 만들었습니다.</p> + +<p>여기서 사용했던 꽤 흥미로운 속성 하나는 <code>text-shadow</code> 문자로, 요소의 문자 콘텐츠에 그림자를 적용해줍니다. 네 개의 값들은 다음과 같습니다:</p> + +<ul> + <li>첫 번째 pixel 값은 그림자의 <strong>수평 오프셋</strong>을 설정합니다 — 얼마나 옆으로 이동시킬 것인지.</li> + <li>두 번째 pixel 값은 그림자의 <strong>수직 오프셋</strong>을 설정합니다 — 얼마나 아래로 이동시킬 것인지.</li> + <li>세 번째 pixel 값은 그림자의 <strong>흐림 반경</strong>을 설정합니다 — 큰 값은 더 흐릿한 그림자를 의미합니다.</li> + <li>네 번째 pixel 값은 그림자의 기본 색상을 설정합니다.</li> +</ul> + +<p>다시, 여러분이 무엇을 확인해 볼 수 있는지 다른 값으로 실험을 해보세요.</p> + +<h3 id="이미지_가운데_정렬">이미지 가운데 정렬</h3> + +<pre class="brush: css">img { + display: block; + margin: 0 auto; +}</pre> + +<p>마지막으로, 이미지를 더 나아보이도록 가운데로 둘 것입니다. 전에 body 에서 했듯이 다시 <code>margin: 0 auto</code> 트릭을 사용해 볼 수 있지만, 무언가 더 해야할 필요가 있습니다. <code>body</code> 요소는 <strong>block level</strong> 입니다. 이것은 페이지의 공간을 차지하고, margin 과 여기에 적용된 다른 여백값을 가질 수 있다는 것을 의미합니다. 반면에 이미지는 <strong>inline</strong> 요소 입니다. 이것은 그렇지 못함을 의미합니다. 따라서 이미지에 margin 을 적용하기 위해서는, <code>display: block;</code> 을 사용해 이미지에 block-level 성질을 주어야 합니다.</p> + +<div class="blockIndicator note"> +<p>노트: 위의 지침에서는 body에 설정된 너비(600 픽셀) 보다 작은 이미지를 사용한다고 가정합니다. 이미지가 더 크면 body가 넘쳐 페이지의 나머지 부분으로 유출됩니다. 이 문제를 해결하려면 1) <a href="https://ko.wikipedia.org/wiki/%EA%B7%B8%EB%9E%98%ED%94%BD_%EC%86%8C%ED%94%84%ED%8A%B8%EC%9B%A8%EC%96%B4">그래픽 편집기</a>를 사용하여 이미지의 너비를 줄이거나 2) 더 작은 값(예: <code>400px</code>) 으로 <code><img></code> 요소에 width 속성을 설정하고 CSS를 사용하여 이미지 크기를 조정할 수 있습니다.</p> +</div> + +<div class="note"> +<p><strong>노트</strong>: 아직 <code>display: block;</code> 과 block-level/inline 차이를 이해하지 못하였더라도 걱정하시마세요. CSS 를 더 깊게 공부하면 이해하실 수 있을것입니다. display 의 여러 값들에 대한 더 많은 정보는 <a href="/en-US/docs/Web/CSS/display">display 참조</a> 페이지에서 찾아보세요.</p> +</div> + +<h2 id="마무리">마무리</h2> + +<p>이 글의 모든 설명을 따라오셨다면, 이와 같이 보이는 페이지가 되실 겁니다. (<a class="external external-icon" href="http://mdn.github.io/beginner-html-site-styled/">여기서</a> 확인하실 수도 있습니다):</p> + +<p><img alt="a mozilla logo, centered, and a header and paragraphs. It now looks nicely styled, with a blue background for the whole page and orange background for the centered main content strip." src="https://mdn.mozillademos.org/files/9455/website-screenshot-final.png" style="display: block; height: 1084px; margin: 0px auto; width: 940px;"></p> + +<p>혹시 막히셨다면, 여러분의 코드와 Github에 있는 우리의 <a href="https://github.com/mdn/beginner-html-site-styled/blob/gh-pages/styles/style.css">예제 코드</a>와 항상 비교해보세요.</p> + +<p>여기서, 우리는 CSS의 겉만 살짝 맛봤습니다. 더 많은 것이 알고 싶으시면 <a href="https://developer.mozilla.org/en-US/Learn/CSS">CSS 배우기</a> 페이지로 가보세요.</p> + +<p>{{PreviousMenuNext("Learn/Getting_started_with_the_web/HTML_basics", "Learn/Getting_started_with_the_web/JavaScript_basics", "Learn/Getting_started_with_the_web")}}</p> + +<h2 id="이번_과목에서는">이번 과목에서는</h2> + +<ul> + <li id="Installing_basic_software"><a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Installing_basic_software">기본 소프트웨어 설치 방법</a></li> + <li id="What_will_your_website_look_like"><a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/What_will_your_website_look_like">What will your website look like?</a></li> + <li id="Dealing_with_files"><a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Dealing_with_files">파일 다루기</a></li> + <li id="HTML_basics"><a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/HTML_basics">HTML 기본 사항</a></li> + <li id="CSS_basics"><a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/CSS_basics">CSS 기본 사항</a></li> + <li id="JavaScript_basics"><a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/JavaScript_basics">JavaScript 기본 사항</a></li> + <li id="Publishing_your_website"><a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Publishing_your_website">웹 사이트 출판</a></li> + <li id="How_the_web_works"><a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/How_the_Web_works">웹 작동 방식</a></li> +</ul> diff --git a/files/ko/learn/getting_started_with_the_web/html_기본/index.html b/files/ko/learn/getting_started_with_the_web/html_기본/index.html new file mode 100644 index 0000000000..530f3fe11f --- /dev/null +++ b/files/ko/learn/getting_started_with_the_web/html_기본/index.html @@ -0,0 +1,234 @@ +--- +title: HTML 기본 +slug: Learn/Getting_started_with_the_web/HTML_기본 +tags: + - Beginner + - HTML + - Learn + - Web + - 'l10n:priority' + - 입문자 +translation_of: Learn/Getting_started_with_the_web/HTML_basics +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Getting_started_with_the_web/Dealing_with_files", "Learn/Getting_started_with_the_web/CSS_basics", "Learn/Getting_started_with_the_web")}}</div> + +<div class="summary"> +<p>HTML(<strong>H</strong>yper<strong>t</strong>ext <strong>M</strong>arkup <strong>L</strong>anguage)은 웹 페이지와 그 내용을 구조화하기 위해 사용하는 코드입니다. 예를 들면, 컨텐트는 여러 개의 문단, 글 머리 목록이 구조화된 것이거나 사진이나 데이터 테이블일 수도 있습니다. 제목과 같이 이 글은 HTML과 그 기능에 대한 기본적인 이해를 제공할 것입니다.</p> +</div> + +<h2 id="그래서_HTML은_무엇일까요">그래서 HTML은 무엇일까요?</h2> + +<p>HTML 은 프로그래밍 언어가 아닙니다; 컨텐츠의 구조를 정의하는 마크업 언어입니다. HTML은 컨텐츠의 서로 다른 부분들을 씌우거나(wrap) 감싸서(enclose) 다른 형식으로 보이게하거나 특정한 방식으로 동작하도록 하는 일련의 <strong>요소({{Glossary("element", "elements")}})</strong>로 이루어져 있습니다. {{Glossary("tag", "tags")}}로 감싸는 것으로 단어나 이미지를 다른 어딘가로 하이퍼링크(hyperlink)하거나 단어들을 이탤릭체로 표시하고 글씨체를 크게 또는 작게 만드는 등의 일을 할 수 있습니다. 예를 들어, 다음과 같은 컨텐츠에 대해:</p> + +<pre>내 고양이는 고약해 +</pre> + +<p>그 한 줄의 문장이 독립적인 구문이길 원한다면, 문단 태그(paragraph tags)로 둘러쌈으로해서 그것이 하나의 문단임을 명시할 수 있습니다:</p> + +<pre class="brush: html"><p>내 고양이는 고약해</p></pre> + +<h3 id="HTML_요소_분석">HTML 요소 분석</h3> + +<p>이 문단 요소에 대해 조금 더 탐구해봅시다.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/9347/grumpy-cat-small.png" style="display: block; height: 255px; margin: 0px auto; width: 821px;"></p> + +<p>이 요소의 주요 부분은 이렇습니다:</p> + +<ol> + <li><strong>여는 태그(opening tag)</strong>: 이것은 요소의 이름으로 구성되고 (여기에서는 p), 여닫는 꺾쇠괄호로 감싸집니다. 이것은 요소가 시작되는 곳, 또는 효과를 시작하는 곳임을 나타냅니다 — 이 예제에서는 문단이 시작되는 위치를 나타냅니다.</li> + <li><strong>닫는 태그(closing tag)</strong>: 이것은 여는 태그와 같지만, 요소의 이름 앞에 전방향 슬래시가 포함된다는 점이 다릅니다. 이것은 요소의 끝을 나타냅니다 — 이 예제에서는 문단이 끝나는 위치를 나타냅니다. 초보자가 가장 흔히 범하는 오류 중 하나가 닫는 태그를 쓰지 않는 것으로 이상한 결과가 표시됩니다.</li> + <li><strong>컨텐츠(content)</strong>: 이것은 요소의 내용(content)으로 이 예제에서는 그냥 텍스트입니다.</li> + <li><strong>요소(element)</strong>: 요소는 여는 태그와 닫는 태그, 그리고 컨텐츠로 이루어집니다.</li> +</ol> + +<p>요소는 속성도 가질 수 있는데, 다음과 같이 사용합니다:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/9345/grumpy-cat-attribute-small.png" style="display: block; height: 156px; margin: 0px auto; width: 1287px;"></p> + +<p>속성은 실제 컨텐츠로 표시되길 원하지 않는 추가적인 정보를 담고 있습니다. 이 예제에서, class 속성을 이용해 나중에 해당 요소를 특정해 스타일이나 다른 정보를 설정할 때 사용할 수 있는 식별자를 지정할 수 있습니다.</p> + +<p>속성이 항상 가져야 하는 것:</p> + +<ol> + <li>요소 이름 (또는 요소가 하나 이상 속성을 이미 가지고 있다면 이전 속성)과 속성 사이에 공백이 있어야 합니다.</li> + <li>속성 이름 뒤에는 등호(=)가 와야 합니다.</li> + <li>속성 값의 앞 뒤에 열고 닫는 인용부호(" 또는 ')가 있어야 합니다.</li> +</ol> + +<h3 id="요소_중첩">요소 중첩</h3> + +<p>여러분은 요소를 다른 요소의 안에 놓을 수 있습니다 — 이것을 <strong>중첩(nesting)</strong>이라고 부릅니다. 우리 고양이는 <strong>아주</strong> 고약하다라고 표시하길 원한다면, 단어를 강조하는 용도로 사용하는{{htmlelement("strong")}} 요소로 "아주"를 감싸면 됩니다:</p> + +<pre class="brush: html"><p>내 고양이는 <strong>아주</strong> 고약해.</p></pre> + +<p>하지만 요소가 적절히 중첩되었는지 확인할 필요가 있습니다: 위의 예제에서 우리는 <p> 요소를 먼저 열었고, 그 다음 strong을 열었기 때문에 strong 요소를 먼저 닫고, 다음으로 p를 닫아야 합니다. 다음은 잘못된 예제 입니다:</p> + +<pre class="brush: html"><p>내 고양이는 <strong>아주 고약해.</p></strong></pre> + +<p>요소들이 적절히 열고 닫혀야 서로가 깔끔하게 안쪽이나 바깥쪽에 있게 됩니다. 만약 이렇게 겹치게 되면, 웹 브라우저는 여러분이 무엇을 표현하려고 했었는지 추측을 해서 화면에 보여주겠지만, 여러분이 의도한 것과 다르게 보여질 수 있습니다. 그러니까 이렇게 하지 마세요!</p> + +<h3 id="빈_요소">빈 요소</h3> + +<p>어떤 요소들은 내용을 갖지 않습니다, 그리고 이것을 <strong>빈 요소(empty elements)</strong>라고 합니다. {{htmlelement("img")}} 요소는 이미 우리 HTML 코드에 있습니다.</p> + +<pre class="brush: html"><img src="images/firefox-icon.png" alt="My test image"></pre> + +<p>이 요소는 두 개의 속성을 포함하고 있으나 닫는 </img> 태그가 없습니다. 이미지 요소는 효과를 주기 위해 컨텐츠를 감싸지 않기 때문입니다. 이 요소의 목적은 HTML 페이지에서 이미지가 나타날 위치에 이미지를 끼워 넣는 것입니다.</p> + +<h3 id="HTML_문서_해부">HTML 문서 해부</h3> + +<p>각 HTML 요소의 기본적인 내용들은 살펴봤지만, 그것만으로는 별로 유용하지 않습니다. 이제 각 요소들이 어떻게 전체 HTML 페이지를 구성하는지 살펴볼 차례입니다. <code>index.html</code> 예제(<a href="/en-US/Learn/Getting_started_with_the_web/Dealing_with_files">파일들 다루기</a> 편에서 처음 봤던)에 넣은 코드를 다시 살펴봅시다:</p> + +<pre class="brush: html"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>My test page</title> + </head> + <body> + <img src="images/firefox-icon.png" alt="My test image"> + </body> +</html></pre> + +<p>살펴볼 것들:</p> + +<ul> + <li><code><!DOCTYPE html></code> — doctype. 아주 오래전 HTML 이 막 나왔을 때 (1991년 2월쯤), doctype은 (자동 오류 확인이나 다른 유용한 것을 의미하는) good HTML로 인정받기 위해 HTML 페이지가 따라야 할 일련의 규칙으로의 연결통로로써 작동하는 것을 의미하였습니다. 하지만, 최근에는 아무도 그런 것들에 대해 신경쓰지 않으며 그저 모든 것이 올바르게 동작하게 하기 위해 포함되어야 할 역사적인 유물일 뿐입니다. 지금은, 그게 알아야 할 전부 입니다.</li> + <li><code><html></html></code> — {{htmlelement("html")}} 요소. 이 요소는 페이지 전체의 컨텐츠를 감싸며, 루트(root) 요소라고도 합니다.</li> + <li><code><head></head></code> — {{htmlelement("head")}} 요소. 이 요소는 HTML 페이지에 포함되어 있는 모든 것들(여러분의 페이지를 조회하는 사람들에게 보여주지 않을 컨텐츠)의 컨테이너 역할을 합니다. 여기에는 {{Glossary("keyword", "keywords")}}와 검색 결과에 표시되길 원하는 페이지 설명, 컨텐츠를 꾸미기 위한 CSS, 문자 집합 선언 등과 같은 것들이 포함됩니다.</li> + <li><code><body></body></code> — {{htmlelement("body")}} 요소. 이것은 페이지에 방문한 모든 웹 사용자들에게 보여주길 원하는 <em>모든</em> 컨텐트를 담고 있으며, 그것이 텍스트일 수도, 이미지, 비디오, 게임, 플레이할 수 있는 오디오 트랙이나 다른 무엇이든 될 수 있습니다.</li> + <li><code><meta charset="utf-8"></code> — 이 요소는 문서가 사용해야 할 문자 집합을 utf-8으로 설정합니다(utf-8 문자 집합에는 인간의 방대한 주류 기록언어에 있는 대부분의 문자가 포함되어 있습니다). 본질적으로 여러분이 사용할 수 있는 어떠한 문자 컨텐트도 다룰 수 있습니다. 이 문자 집합을 설정하지 않을 이유가 없으며, 그렇게 설정하면 나중에 발생할 수 있는 일부 문제를 피할 수 있습니다.</li> + <li><code><title></title></code> — {{htmlelement("title")}} 요소. 이 요소는 페이지의 제목을 설정하는 것으로 페이지가 로드되는 브라우저의 탭에 이 제목이 표시됩니다. 이 요소는 북마크나 즐겨찾기에서 페이지를 설명하는 것으로도 사용됩니다.</li> +</ul> + +<h2 id="이미지">이미지</h2> + +<p>{{htmlelement("img")}} 요소를 다시 살펴보도록 합시다:</p> + +<pre class="brush: html"><img src="images/firefox-icon.png" alt="My test image"></pre> + +<p>앞에서 설명한 것처럼 이 요소는 이미지가 나타나야 할 위치에 이미지를 끼워 넣습니다. 이미지 파일의 경로를 포함하는 <code>src</code> (source) 속성을 통해 이러한 일을 합니다.</p> + +<p> <code>alt</code> (alternative) 속성도 존재합니다. — 이 속성에는 다음과 같은 이유로 이미지를 볼 수 없는 사용자들을 위한 설명문(descriptive text)을 지정할 수 있습니다.:</p> + +<ol> + <li>시각 장애자인 경우. 시각 장애가 심한 사용자들은 alt 텍스트(대체 텍스트)를 읽어주는 스크린 리더라는 도구를 자주 사용합니다.</li> + <li>무언가 잘못되어서 이미지를 표시할 수 없는 경우. 예를 들면, <code>src</code> 속성 안의 경로를 일부러 틀리게 변경해보세요. 저장한 후에 페이지를 다시 열면, 이미지가 표시되어야할 위치에 다음과 같은 것을 보게 될 것입니다.</li> +</ol> + +<p><img alt="" src="https://mdn.mozillademos.org/files/9349/alt-text-example.png" style="display: block; height: 36px; margin: 0px auto; width: 108px;"></p> + +<p>alt 텍스트에서 핵심 단어는 "설명적인 문자(descriptive text)" 입니다. 여러분이 작성하는 alt 텍스트는 독자에게 이미지가 전달하는 어떤 것에 대해 좋은 아이디어를 가지기에 충분한 정보를 제공해야 합니다. 이 예제에서 "My test image"라는 현재의 텍스트는 전혀 좋지 않습니다. Firefox 로고에 대해서는 "파이어폭스 로고: 지구를 둘러싼 타오르는 여우"가 훨씬 나은 대안이될 수 있습니다.</p> + +<p>지금 여러분의 이미지를 위한 더 나은 alt 텍스트를 만들어보세요.</p> + +<div class="note"> +<p><strong>노트</strong>: 접근성에 대한 더 많은 것은 <a href="/en-US/docs/Web/Accessibility">MDN의 페이지 접근성 시작하기</a>에서 찾아보세요.</p> +</div> + +<h2 id="문자_나타내기">문자 나타내기</h2> + +<p>여기에서는 문자를 나타내기 위해 사용하는 몇 개의 기본적인 HTML 엘리먼트를 다룰 것입니다.</p> + +<h3 id="제목">제목</h3> + +<p>제목 요소는 여러분이 내용의 특정 부분이 제목 또는 내용의 하위 제목임을 구체화 할 수 있게 해줍니다. 책에 중심 제목이 있고 그 다음 각각의 장에 제목을 가지고, 그리고 그 안에 부제가 있는 것과 같은 방식으로 HTML 문서도 제목들을 갖습니다. HTML 은 여섯 단계의 제목을 갖고, {{htmlelement("h1")}}–{{htmlelement("h6")}} 여러분은 아마 3-4 만을 주로 사용하게 될겁니다:</p> + +<pre class="brush: html"><h1>My main title</h1> +<h2>My top level heading</h2> +<h3>My subheading</h3> +<h4>My sub-subheading</h4></pre> + +<p>지금 한번 해보세요, 여러분의 HTML 페이지에 있는 {{htmlelement("img")}} 요소 위에 적당한 제목을 추가합시다.</p> + +<h3 id="문단">문단</h3> + +<p>위에서 설명했듯이, {{htmlelement("p")}} 요소는 문자의 문단을 포함하기 위한 것입니다; 일반적인 문자 내용을 나타낼 때 많이 사용하게 될 것입니다:</p> + +<pre class="brush: html"><p>This is a single paragraph</p></pre> + +<p><strong>간단한 문자 (<a href="/en-US/Learn/Getting_started_with_the_web/What_should_your_web_site_be_like"><em>웹사이트의 외관은 어떻게 할까요?</em></a> 에서 보셨을겁니다)를 하나 또는 몇 개의 문단에 추가하고, <img> 요소 바로 아래 둡시다.</strong></p> + +<h3 id="목록">목록</h3> + +<p>많은 웹의 내용은 목록이기 때문에, HTML은 이것을 위한 특별한 요소를 가지고 있습니다. 목록을 나타내는 것은 항상 최소 두 개의 요소로 구성됩니다. 가장 일반적인 목록의 종류는 순서가 있는 것과 순서 없는 것이 있습니다.</p> + +<ol> + <li><strong>순서 없는 목록은</strong> 쇼핑 목록과 같이 항목의 순서에 관계가 없는 목록을 위한 것입니다. {{htmlelement("ul")}} 요소로 둘러 쌓여 있습니다.</li> + <li><strong>순서 있는 리스트</strong>는 조리법처럼 항목의 순서가 중요한 목록을 위한 것입니다. {{htmlelement("ol")}} 요소로 둘러 쌓여 있습니다.</li> +</ol> + +<p>목록의 각 항목은 {{htmlelement("li")}} (목록 항목) 요소 안에 놓여야 합니다.</p> + +<p>그러니까 예를 들면, 만약 아래 문단의 한 부분을 목록으로 분리하길 원한다면:</p> + +<pre class="brush: html"><p>At Mozilla, we’re a global community of technologists, thinkers, and builders working together ... </p></pre> + +<p>이렇게 해볼 수 있습니다:</p> + +<pre class="brush: html"><p>At Mozilla, we’re a global community of</p> + +<ul> + <li>technologists</li> + <li>thinkers</li> + <li>builders</li> +</ul> + +<p>working together ... </p></pre> + +<p><strong>여러분의 예시 페이지에서 순서 있는 목록과 순서 없는 목록을 추가해보세요.</strong></p> + +<h2 id="연결">연결</h2> + +<p>연결은 아주 중요합니다 — 이것은 웹을 웹으로 만들어줍니다. 연결을 하기 위해, 간단한 요소를 사용할 필요가 있습니다 — {{htmlelement("a")}} — <em>a</em> 는 "anchor" 의 약자입니다. 문장 안의 어떤 단어를 링크로 만들기 위해, 아래의 순서를 따르시면 됩니다:</p> + +<ol> + <li>어떤 단어를 선택하세요. "Mozilla Manifesto" 를 선택하겠습니다.</li> + <li>문자를 <a> 요소로 감쌉니다, 이렇게요: + <pre class="brush: html"><a>Mozilla Manifesto</a></pre> + </li> + <li><a> 요소에 href 속성을 줍니다, 이렇게요: + <pre class="brush: html"><a href="">Mozilla Manifesto</a></pre> + </li> + <li>이 속성의 값에 여러분이 연결하길 원하는 웹 주소를 채웁니다.: + <pre class="brush: html"><a href="https://www.mozilla.org/en-US/about/manifesto/">Mozilla Manifesto</a></pre> + </li> +</ol> + +<p>만약 웹 주소의 시작부분에 <em>프로토콜</em>이라 불리는 https:// 또는 http:// 부분을 빼먹으셨다면 예상하지 못한 결과를 얻을 것입니다. 이렇게 링크를 만든 후에, 원하는 곳으로 이동하는지 클릭해보세요.</p> + +<div class="note"> +<p><code>처음에는 href</code> 라는 속성 이름이 꽤 어렵게 보일수도 있습니다. 만약 기억하기가 어려우시다면, 이것은 <em><strong>h</strong>ypertext <strong>ref</strong>erence</em>(<span>하이퍼 텍스트 참조)</span>를 나타낸다는 것을 기억하세요.</p> +</div> + +<p><strong>아직 여러분의 페이지에 링크를 추가하지 않으셨다면, 지금 추가해보세요.</strong></p> + +<h2 id="마무리">마무리</h2> + +<p>이 글의 모든 설명을 따라오셨다면, 이와 같이 보이는 페이지가 될 겁니다. (<a href="http://mdn.github.io/beginner-html-site/">여기서</a>도 볼 수 있습니다):<br> + <br> + <img alt="A web page screenshot showing a firefox logo, a heading saying mozilla is cool, and two paragraphs of filler text" src="https://mdn.mozillademos.org/files/9351/finished-test-page-small.png" style="display: block; height: 838px; margin: 0px auto; width: 716px;"></p> + +<p>잘 안 된다면, 여러분의 코드를 Github에 있는 <a href="https://github.com/mdn/beginner-html-site/blob/gh-pages/index.html">예제 코드</a>를 비교해 볼 수 있습니다. </p> + +<p>여기서, 우리는 HTML의 겉을 살짝 맛봤습니다. 더 알아보기 위해, <a href="/en-US/Learn/HTML">HTML 배우기</a> 페이지로 가보세요.</p> + +<p>{{PreviousMenuNext("Learn/Getting_started_with_the_web/Dealing_with_files", "Learn/Getting_started_with_the_web/CSS_basics", "Learn/Getting_started_with_the_web")}}</p> + + + +<h2 id="이번_모듈에서는">이번 모듈에서는</h2> + +<ul> + <li id="Installing_basic_software"><a href="https://wiki.developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Installing_basic_software">기본 소프트웨어 설치하기</a></li> + <li id="What_will_your_website_look_like"><a href="https://wiki.developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/What_will_your_website_look_like">여러분의 웹사이트는 어떤 모습일까요?</a></li> + <li id="Dealing_with_files"><a href="https://wiki.developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Dealing_with_files">파일 다루기</a></li> + <li id="HTML_basics"><a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/HTML_basics">HTML 기본 사항</a></li> + <li id="CSS_basics"><a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/CSS_basics">CSS 기본 사항</a></li> + <li id="JavaScript_basics"><a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/JavaScript_basics">JavaScript 기본 사항</a></li> + <li id="Publishing_your_website"><a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Publishing_your_website">웹 사이트 출판</a></li> + <li id="How_the_web_works"><a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/How_the_Web_works">웹 작동 방식</a></li> +</ul> diff --git a/files/ko/learn/getting_started_with_the_web/index.html b/files/ko/learn/getting_started_with_the_web/index.html new file mode 100644 index 0000000000..5ccbd0ea75 --- /dev/null +++ b/files/ko/learn/getting_started_with_the_web/index.html @@ -0,0 +1,64 @@ +--- +title: Web과 함께 시작하기 +slug: Learn/Getting_started_with_the_web +tags: + - Beginner + - CSS + - Design + - Guide + - HTML + - Index + - 'l10n:priority' + - 가이드 + - 초보자 +translation_of: Learn/Getting_started_with_the_web +--- +<div>{{LearnSidebar}}</div> + +<div class="summary"> +<p><em>Web과 함께 시작하기(Getting stated with the Web)</em>는 여러분에게 웹 개발의 실질적인 측면을 소개하는 간결한 시리즈입니다. 여러분은 간단한 웹페이지를 만들 때 필요한 도구를 설치하고 여러분의 코드를 게시할 것입니다.</p> +</div> + +<h2 id="당신의_첫_번째_웹사이트_줄거리">당신의 첫 번째 웹사이트 줄거리</h2> + +<p>전문적인 웹사이트를 생성하기 위해서는 매우 많은 작업이 필요합니다. 그러니 웹 개발이 처음이라면, 처음은 작게 시작해보세요. 지금 당장 Facebook을 만들 수는 없지만, 자신만의 간단한 온라인 웹사이트를 만드는 건 그리 어렵지 않으니 여기부터 시작하겠습니다.</p> + +<p>아래 나열한 항목을 순서대로 진행하면 백지부터 시작해서 첫 웹페이지를 인터넷에 띄울겁니다. 시작합시다!</p> + +<h3 id="기본_소프트웨어_설치하기Installing_basic_software"><a href="/ko/docs/Learn/Getting_started_with_the_web/Installing_basic_software">기본 소프트웨어 설치하기(Installing basic software)</a></h3> + +<p>웹사이트 제작을 위한 도구는 아주 많습니다. 이제 막 시작한다면 수도 없이 많은 코드 편집기와 프레임워크, 테스트 도구 때문에 혼란스러울 겁니다.<a href="/ko/docs/Learn/Getting_started_with_the_web/%EA%B8%B0%EB%B3%B8_%EC%86%8C%ED%94%84%ED%8A%B8%EC%9B%A8%EC%96%B4_%EC%84%A4%EC%B9%98%ED%95%98%EA%B8%B0">기본 소프트웨어 설치하기</a>에서는 기본적인 웹 개발을 시작하기 위해 필요한 소프트웨어를 어떻게 설치할 수 있는지 차근차근 알려드립니다.</p> + +<h3 id="웹사이트의_외관은_어떻게_할까요What_will_your_website_look_like"><a href="/ko/docs/Learn/Getting_started_with_the_web/What_will_your_website_look_like">웹사이트의 외관은 어떻게 할까요?(What will your website look like?)</a></h3> + +<p>여러분의 웹사이트를 위한 코드 작성을 하기 전에, 먼저 계획을 세워야 합니다. 어떤 정보들을 강조할 건가요? 어떤 글꼴이나 색상을 사용할 것인가요? <a href="/ko/docs/Learn/Getting_started_with_the_web/What_will_your_website_look_like">웹사이트의 외관은 어떻게 할까요?</a>에서 우리는 여러분이 사이트의 내용이나 디자인을 계획하기 위해 따라할 수 있는 간단한 방법을 제공할 것입니다.</p> + +<h3 id="파일_다루기Dealing_with_files"><a href="/ko/docs/Learn/Getting_started_with_the_web/Dealing_with_files">파일 다루기(Dealing with files)</a></h3> + +<p>웹사이트는 많은 파일(문자, 코드, 스타일시트, 미디어, 등등)로 이루어져 있습니다. 웹사이트를 만들 때, 여러분은 합리적인 구조로 여러 파일을 모으고 서로 상호 작용이 가능한지 확인해야 합니다. <a href="/ko/docs/Learn/Getting_started_with_the_web/%ED%8C%8C%EC%9D%BC%EB%93%A4_%EB%8B%A4%EB%A3%A8%EA%B8%B0">파일 다루기</a>에서 여러분의 웹사이트를 위해 합리적인 파일 구조를 설정하는 방법과 여러분이 알아야 할 문제들을 설명할 것입니다.</p> + +<h3 id="HTML_기본"><a href="/ko/docs/Learn/Getting_started_with_the_web/HTML_기본">HTML 기본</a></h3> + +<p>HTML(Hypertext Markup Language)은 여러분의 웹 컨텐츠를 구조화하고, 의미와 의도를 주기위해 사용되는 코드입니다. 예를 들면, 내 컨텐츠가 문단의 집합인지, 또는 목차(*)의 리스트인지? 내 페이지에 이미지를 넣어야 하는지? 데이터 테이블이 필요한지? 여러분을 난처하지 않게하면서, <a href="/ko/docs/Learn/Getting_started_with_the_web/HTML_기본">HTML 기본</a>은 여러분이 HTML에 익숙해질 수 있도록 충분한 정보를 제공할 것입니다.</p> + +<h3 id="CSS_기본"><a href="/ko/docs/Learn/Getting_started_with_the_web/CSS_basics">CSS 기본</a></h3> + +<p>CSS(Cascading Style Sheets)는 여러분의 웹사이트를 꾸밀 때 사용하는 코드입니다. 예를 들면, 글자 색을 검정과 빨강 중 어느걸 하실건가요? 아니면 컨텐츠를 화면 어디에 표시해야 하나요? 웹사이트를 장식하려면 어떤 배경 이미지나 색을 사용하실 건가요? <a href="/ko/docs/Learn/Getting_started_with_the_web/CSS_basics">CSS 기본</a>으로 시작에 필요한 모든걸 준비해보세요.</p> + +<h3 id="JavaScript_기본"><a href="/ko/docs/Learn/Getting_started_with_the_web/JavaScript_basics">JavaScript 기본</a></h3> + +<p>JavaScript는 여러분이 인터렉티브한 기능을 웹사이트에 추가할 때 사용하는 프로그래밍 언어입니다. 예를 들면 게임, 버튼이 눌리거나 폼에 정보가 입력되었을 때 발생하는 것, 동적인 스타일 효과, 애니매이션 등이 있습니다. <a href="/ko/docs/Learn/Getting_started_with_the_web/JavaScript_basics">JavaScript 기본</a>은 여러분께 이 흥미로운 언어로 가능한 것들에 대한 것과 어떻게 시작할 수 있는지에 대한 아이디어를 제공할 것입니다.</p> + +<h3 id="웹사이트_출판하기"><a href="/ko/docs/Learn/Getting_started_with_the_web/Publishing_your_website">웹사이트 출판하기</a></h3> + +<p>일단 여러분이 코드 작성과 웹사이트를 위한 파일 구성을 마쳤다면, 사람들이 찾아볼 수 있도록 이 모든 것을 온라인에 둘 필요가 있습니다. <a href="/ko/docs/Learn/Getting_started_with_the_web/Publishing_your_website">예제 코드 출판하기</a>는 여러분이 간단한 예제 코드를 어떻게 최소한의 노력으로 얻을 수 있는지 설명할 것입니다.</p> + +<h3 id="웹의_동작_방식"><a href="/ko/docs/Learn/Getting_started_with_the_web/How_the_Web_works">웹의 동작 방식</a></h3> + +<p>여러분이 가장 선호하는 웹사이트에 접근할 때, 여러분이 모르는 많은 복잡한 것들이 눈에 띄지 않는 곳에서 발생합니다. <a href="/ko/docs/Learn/Getting_started_with_the_web/How_the_Web_works">웹의 동작 방식</a>은 여러분이 컴퓨터로 웹페이지를 볼 때 발생하는 것들에 대한 개략적인 설명을 할 것입니다.</p> + +<h2 id="같이_보기">같이 보기</h2> + +<p><a href="https://www.youtube.com/playlist?list=PLo3w8EB99pqLEopnunz-dOOBJ8t-Wgt2g">Web Demystified</a>: 웹 개발을 처음 시작하는 분을 위해 웹 기초를 설명하는 뛰어난 비디오 시리즈입니다. <a href="https://twitter.com/JeremiePat">Jérémie Patonnier</a>가 제작했습니다.</p> + +<p><a href="https://wiki.developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web/The_web_and_web_standards">The web and web standards</a>: 이 글은 웹에 대한 유용한 배경지식을 알려줍니다. -- 웹이 어떻게 생겼는지, 웹의 표준 기술이 무엇인지, 어떻게 같이 작동하는지, 왜 "웹 개발자"가 직업으로 삼기 좋은지, 그리고 관련 과목들을 공부하면서 어떤 것들이 최선의 관행인지 알려줍니다.</p> diff --git a/files/ko/learn/getting_started_with_the_web/javascript_basics/index.html b/files/ko/learn/getting_started_with_the_web/javascript_basics/index.html new file mode 100644 index 0000000000..05e48cef49 --- /dev/null +++ b/files/ko/learn/getting_started_with_the_web/javascript_basics/index.html @@ -0,0 +1,427 @@ +--- +title: JavaScript 기본 +slug: Learn/Getting_started_with_the_web/JavaScript_basics +tags: + - 자바스크립트 +translation_of: Learn/Getting_started_with_the_web/JavaScript_basics +--- +<p>{{LearnSidebar}}</p> + +<p>{{PreviousMenuNext("Learn/Getting_started_with_the_web/CSS_basics", "Learn/Getting_started_with_the_web/Publishing_your_website", "Learn/Getting_started_with_the_web")}}</p> + +<div class="summary"> +<p>자바스크립트는 여러분의 웹사이트에 상호작용성(예를 들면, 게임, 버튼이 눌리거나 폼에 자료가 입력될 때 반응, 동적인 스타일링과 애니메이션)을 더해 주는 프로그래밍 언어 입니다. 이 글은 여러분이 이 흥미로운 언어를 시작하는 것을 도와드리고 가능한 것에 대한 아이디어를 제공할 것입니다.</p> +</div> + +<h2 id="자바스크립트는_무엇인가">자바스크립트는 무엇인가?</h2> + +<p>{{Glossary("JavaScript")}} (줄여서 "JS")는 {{Glossary("HTML")}} 문서에 적용될 때, 웹사이트상에서 동적 상호작용성을 제공할 수 있는 완전한 동적 프로그래밍 언어({{Glossary("Dynamic programming language", "dynamic programming language")}})입니다. 이것은 Mozilla 프로젝트, Mozilla 재단, 그리고 Mozilla 법인의 공동 창설자인 Brendan Eich 에 의해 만들어졌습니다.</p> + +<p>자바스크립트는 믿을 수 없을 정도로 다재다능합니다. 캐러셀 기능(이미지를 차례대로 바꿔볼 수 있는 기능)을 가진 이미지 갤러리, 변화하는 레이아웃, 그리고 버튼이 클릭될 때의 반응과 같은 간단한 것부터 시작할 것입니다. 경험이 더 쌓이면 게임이나 움직이는 2D 및 3D 그래픽, 포괄적인 데이터베이스 지향적인 앱과 더 많은 것을 만들 수 있을 것입니다!</p> + +<p>자바스크립트 그 자체는 상당히 작지만 아주 유연합니다. 개발자들은 코어 자바스크립트 언어(core JavaScript language) 위에서 동작하는 많은 다양한 도구를 개발해왔는데, 이를 이용하면 최소한의 수고로 엄청나게 많은 확장 기능을 사용할 수 있습니다. 여기에는 다음과 같은 것들이 포함됩니다:</p> + +<ul> + <li>브라우저 응용 프로그래밍 인터페이스 ({{Glossary("API","APIs")}}) — 브라우저에 내장된 API로 HTML을 동적으로 생성하고 CSS 스타일을 설정하거나, 사용자의 웹캠으로부터 비디오 스트림을 수집하거나 조작하는 것, 또는 3D 그래픽이나 오디오 샘플을 생성하는 것과 같은 다양한 기능을 제공합니다.</li> + <li>제3자 (third-party) API를 활용해 개발자는 트위터나 페이스북 같은 다른 컨텐츠 공급사부터 제공되는 기능을 자신의 사이트에 통합할 수 있습니다.</li> + <li>써드파티 프레임워크와 라이브러리를 여러분의 HTML에 적용함으로써 사이트와 어플리케이션을 빠르게 구축할 수 있습니다.</li> +</ul> + +<p>이 글은 자바스크립트를 가볍게 설명하기 위한 목적으로 작성되어, 지금 단계에서는 여러분을 혼란스럽게 만들지 않기 위해 코어 자바스크립트 언어와 위에 나열된 다른 도구 사이에 어떤 차이가 있는지 상세하게 언급하지 않을 것입니다. 이와 관련해서는 MDN의 나머지 글이나 <a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript">자바스크립트 학습 영역(JavaScript learning area)</a>에서 자세하게 배울 수 있습니다.</p> + +<h2 id="Hello_world_예시">"Hello world" 예시</h2> + +<p>위의 섹션은 정말 흥분되게 만드는데 — 자바스크립트는 가장 활발한 웹 기술 중 하나이고, 이것을 잘 활용할 수 있게되면 여러분의 웹사이트는 새로운 차원의 힘과 창의성을 가지게될 것입니다.</p> + +<p>하지만, 자바스크립트에 익숙해지는 것은 HTML과 CSS에 익숙해지는 것보다는 조금 더 어렵습니다. 여러분은 간단한 것부터 시작해 조금씩 지속적으로 꾸준히 나가야 할 것입니다. 시작하기에 앞서 "Hello world!" 예제(<a href="https://en.wikipedia.org/wiki/%22Hello,_World!%22_program">기본적인 프로그래밍 예제의 표준</a>)를 작성해 봄으로써 어떻게 페이지에 기본적인 자바스크립트를 추가할 수 있는지를 보여드릴 것입니다.</p> + +<div class="warning"> +<p><strong>중요</strong>: 여러분이 우리의 나머지 코스를 따라오지 않으셨다면, <a href="https://github.com/mdn/beginner-html-site-styled/archive/gh-pages.zip">이 예제 코드를 다운 </a>받으시고 이것을 시작점으로 사용하세요.</p> +</div> + +<ol> + <li>먼저, 여러분의 테스트 사이트로 가서 <code>scripts</code>라는 새로운 폴더를 생성하세요. 다음으로 방금 만든 스크립트 폴더 내에 <code>main.js</code> 라는 새 파일을 생성하세요. 그 파일을 <code>scripts</code> 폴더에 저장하시면 됩니다.</li> + <li>다음은, <code>index.html</code> 파일로 가서 닫는 <code></body></code> 태그의 바로 앞에 새로운 줄을 추가하고 다음 요소를 입력하세요: + <pre class="brush: html language-html"><code class="language-html"><span class="script token"><span class="tag token"><span class="tag token"><span class="punctuation token"><</span>script</span> <span class="attr-name token">src</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>scripts/main.js<span class="punctuation token">"</span></span><span class="punctuation token">></span></span><span class="tag token"><span class="tag token"><span class="punctuation token"></</span>script</span><span class="punctuation token">></span></span></span></code></pre> + </li> + <li>이것은 기본적으로 CSS 참조를 위해 {{htmlelement("link")}} 요소를 추가할 때와 같은 일을 하는 것입니다 — 페이지에 자바스크립트를 적용하여 HTML에 영향을 줄 수 있습니다(CSS와 함께, 페이지의 다른 것들에도).</li> + <li>이제 <code>main.js</code> 파일에 다음 코드를 추가하세요: + <pre class="brush: js">let myHeading = document.querySelector('h1'); +myHeading.textContent = 'Hello world!';</pre> + </li> + <li>끝으로, HTML과 자바스크립트 파일이 저장되었는지 확인하시고, 브라우저에서 <code>index.html</code>를 열어보세요. 여러분은 다음과 같은 것을 보게 될 것입니다:<img alt="" src="https://mdn.mozillademos.org/files/9543/hello-world.png" style="display: block; height: 236px; margin: 0px auto; width: 806px;"></li> +</ol> + +<div class="note"> +<p><strong>참고</strong>: {{htmlelement("script")}} 요소를 HTML 파일의 맨 아래쪽 근처에 둔 이유는 HTML은 파일 내에 나타나는 순서대로 브라우저에 로드(load)되기 때문입니다. 만약 자바스크립트가 먼저 로드되고 자신의 아래 쪽에 있는 HTML에 영향을 준다고 하면, 영향을 줄 HTML 보다 먼저 자바스크립트가 로드되기 때문에 작동하지 않을 것입니다. 따라서, HTML 페이지의 맨 아래쪽 근처에 자바스크립트를 두는 것이 최고의 전략입니다.</p> +</div> + +<h3 id="무슨_일이_발생했나요">무슨 일이 발생했나요?</h3> + +<p>자바스크립트를 이용하여 본문 제목 텍스트를 "Hello world!"로 변경하였습니다. 먼저 {{domxref("Document.querySelector", "querySelector()")}}라는 함수를 이용하여 본문 제목에 대한 참조를 <code>myHeading</code>이라는 변수에 저장하였습니다. 이는 CSS 선택자(selectors)를 이용하는 것과 아주 유사합니다. 어떤 요소에 뭔가 하길 원하면, 먼저 그것을 선택해야 합니다.</p> + +<p>그 다음, <code>myHeading</code> 변수의 <code>{{domxref("Node.textContent", "textContent")}}</code> 프로퍼티의 값(본문 제목의 컨텐츠를 나타내는 것)을 "Hello world!"로 설정했습니다.</p> + +<div class="note"> +<p><strong>참고</strong>: 위에서 사용한 두 기능은 모두 문서를 조작(manipulate)할 때 사용하는 <a href="/en-US/docs/Web/API/Document_Object_Model">문서 객체 모델(Document Object Model;DOM) API</a>의 일부입니다.</p> +</div> + +<h2 id="언어_기본_특강">언어 기본 특강</h2> + +<p>이 모든 것이 작동하는 방식에 대해 더 잘 이해할 수 있도록 자바스크립트 언어의 핵심적인 특징을 몇 가지 설명드리겠습니다. 이런 특징은 모든 프로그래밍 언어에서 공통적으로 나타나는 것에 불과하므로 이런 원칙을 숙지한다면 어떤 것이라도 프로그램할 수 있게 될 것입니다!.</p> + +<div class="warning"> +<p><strong>중요</strong>: 이 글에서는, 어떤 일이 발생하는지 확인 할 수 있게 자바스크립트 콘솔에 예제 코드를 입력합니다. 자바스크립트 콘솔에 대한 더 자세한 사항은, <a href="/ko/Learn/Discover_browser_developer_tools">브라우저 개발 도구 탐험하기</a>를 보세요.</p> +</div> + +<h3 id="변수">변수</h3> + +<p>{{Glossary("Variable", "Variables")}}는 여러분이 값을 저장할 수 있는 컨테이너입니다. 변수를 선언할 때 <code>var</code> 또는 <code>let</code> 키워드 뒤에 원하는 어떤 이름을 붙이면 됩니다:</p> + +<pre class="brush: js">let myVariable;</pre> + +<div class="note"> +<p><strong>참고</strong>: 한 줄의 끝에 있는 세미콜론은 문(statement)의 끝을 나타냅니다; 한 줄에 있는 여러 문을 분리할 필요가 있을 때에만 반드시 필요합니다. 하지만, 어떤 사람은 각 문의 끝에 세미콜론을 넣는 것이 좋은 습관이라 믿습니다. 언제 세미콜론을 넣고 언제 넣으면 안되는지에 대한 다른 규칙이 있습니다 — 자세한 사항은 <a href="http://news.codecademy.com/your-guide-to-semicolons-in-javascript/">자바스크립트의 세미콜론 안내(Your Guide to Semicolons in JavaScript)</a>를 참고하세요.</p> +</div> + +<div class="note"> +<p><strong>참고</strong>: 거의 모든 이름을 변수 이름으로 사용할 수 있지만, 몇 가지 제한이 있습니다 (<a href="http://www.codelifter.com/main/tips/tip_020.shtml">변수 이름 규칙에 관한 글</a> 을 보세요). 변수 이름에 대해 확신이 없다면, <a href="https://mothereff.in/js-variables">변수명 체크하기(check your variable name)</a>에서 적절한 변수명인지 확인해 볼 수 있습니다.</p> +</div> + +<div class="note"> +<p><strong>참고</strong>: 자바스크립트는 대소문자를 구분합니다 — <code>myVariable</code>은 <code>myvariable</code>과는 다른 변수입니다. 만약 코드에 문제가 생겼다면, 대소문자를 확인해보세요!</p> +</div> + +<div class="note"> +<p><strong>참고</strong>: <code>var</code> 와 <code>let</code> 의 차이에 대한 자세한 사항은 <a href="/en-US/docs/Learn/JavaScript/First_steps/Variables#The_difference_between_var_and_let">The difference between var and let</a>를 참고하세요.</p> +</div> + +<p>변수를 선언한 후에, 값을 할당할 수 있습니다:</p> + +<pre class="brush: js">myVariable = 'Bob';</pre> + +<p>원한다면, 변수 선언과 값을 주는 작업을 한 줄로 처리할 수 있습니다:</p> + +<pre class="brush: js">let myVariable = 'Bob';</pre> + +<p>이름으로 변수를 호출하기만 하면 값을 추출할 수 있습니다.</p> + +<pre class="brush: js">myVariable;</pre> + +<p>변수에 어떤 값을 준 후, 나중에 변경할 수도 있습니다.</p> + +<pre>let myVariable = 'Bob'; +myVariable = 'Steve';</pre> + +<p>변수는 여러 <a href="/ko/docs/Web/JavaScript/Data_structures">자료형</a>을 가질 수 있다는 점을 기억하세요:</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="row">변수</th> + <th scope="col">설명</th> + <th scope="col">예시</th> + </tr> + </thead> + <tbody> + <tr> + <th scope="row">{{Glossary("String")}}</th> + <td>문자열로도 알려진 일련의 텍스트. 그 값이 문자열이라는 것을 나타내기 위해서는 인용부호로 둘러싸야 합니다.</td> + <td><code>let myVariable = 'Bob';</code></td> + </tr> + <tr> + <th scope="row">{{Glossary("Number")}}</th> + <td>숫자. 숫자는 인용부호를 사용하지 않습니다.</td> + <td><code>let myVariable = 10;</code></td> + </tr> + <tr> + <th scope="row">{{Glossary("Boolean")}}</th> + <td>참/거짓 값. <code>true</code>와 <code>false</code>라는 단어는 JS의 특별한 키워드이며, 인용부호가 필요 없습니다.</td> + <td><code>let myVariable = true;</code></td> + </tr> + <tr> + <th scope="row">{{Glossary("Array")}}</th> + <td>여러 값을 하나의 단일 참조(single reference)에 저장할 수 있도록 해주는 구조</td> + <td><code>let myVariable = [1,'Bob','Steve',10];</code><br> + 해당 배열의 각 멤버는 다음과 같이 참조할 수 있습니다: <code>myVariable[0]</code>, <code>myVariable[1]</code>, etc.</td> + </tr> + <tr> + <th scope="row">{{Glossary("Object")}}</th> + <td>기본적으로, 무엇이든. 자바스크립트의 모든 것은 객체(object)이며 어떤 변수에 저장될 수 있습니다. 학습하는 동안 이 점을 기억하세요.</td> + <td><code>let myVariable = document.querySelector('h1');</code><br> + 위의 모든 예시도 마찬가지입니다.</td> + </tr> + </tbody> +</table> + +<p>그러면 변수가 왜 필요할까요? 글쎄요, 변수는 프로그래밍에서 흥미로운 어떤 일을 하기 위해 필요합니다. 만약 값이 바뀔 수 없다면, 개인별 맞춤 인사 메시지나 이미지 갤러리에 표시되는 이미지를 바꾼다든지 하는 동적인 일을 할 수 없습니다.</p> + +<h3 id="주석">주석</h3> + +<p>CSS에서 했던 것처럼 자바스크립트 코드 안에 주석을 넣을 수 있습니다:</p> + +<pre class="brush: js">/* +사이에 있는 모든 것은 주석입니다. +*/</pre> + +<p>줄바꿈을 할 필요가 없는 주석이라면, 두 개의 슬래시 뒤에 주석을 놓는 것이 더 쉽습니다:</p> + +<pre class="brush: js" style="font-size: 14px;">// 이것은 주석입니다 +</pre> + +<h3 id="연산자">연산자</h3> + +<p><code>{{Glossary("operator")}}</code>는 두 값(또는 변수)로부터 결과를 만들어내는 수학 기호입니다. 다음 테이블에서 가장 간단한 연산자 몇 개와 자바스크립트 콘솔(console)에서 실행해 볼 수 있는 예제 몇 개를 같이 볼 수 있습니다.</p> + +<table class="standard-table" style="height: 755px; width: 852px;"> + <thead> + <tr> + <th scope="row">연산자</th> + <th scope="col">설명</th> + <th scope="col">기호</th> + <th scope="col">예시</th> + </tr> + </thead> + <tbody> + <tr> + <th scope="row">더하기</th> + <td> + <p>두 수를 합치거나, 또는 두 문자열을 하나로<br> + 붙일 때 사용합니다.</p> + </td> + <td><code>+</code></td> + <td><code>6 + 9;<br> + "Hello " + "world!";</code></td> + </tr> + <tr> + <th scope="row"> + <p>빼기,<br> + 곱하기,<br> + 나누기 </p> + </th> + <td>예상하는 바와 같이 기초수학에서 하는 것과<br> + 동일하게 동작합니다.</td> + <td><code>-</code>, <code>*</code>, <code>/</code></td> + <td><code>9 - 3;<br> + 8 * 2; // JS 에서의 곱하기는 별표입니다<br> + 9 / 3;</code></td> + </tr> + <tr> + <th scope="row">할당</th> + <td>이것에 대해서는 이미 보았습니다: 값을 어떤 변수에 할당합니다.</td> + <td><code>=</code></td> + <td><code>let myVariable = 'Bob';</code></td> + </tr> + <tr> + <th scope="row">동등</th> + <td>두 값이 서로 같은지 테스트하여 <code>true</code>/<code>false</code><br> + (불리언) 결과를 반환합니다.</td> + <td><code>===</code></td> + <td><code>let myVariable = 3;<br> + myVariable === 4;</code></td> + </tr> + <tr> + <th scope="row">부정,<br> + 다름</th> + <td>연산자 뒤쪽의 값에 대해 논리적으로 반대인 값을 반환합니다;<code>true</code>를 <code>false</code>로 바꾸는 등.<br> + 동등 연산자와 함께 사용할 경우 부정 연산자는 두 값이 같지 않은지 여부를 테스트합니다.</td> + <td><code>!</code>, <code>!==</code></td> + <td> + <p>기본 표현은 <code>true</code>이지만 비교는 <code>false</code>를 반환합니다 왜냐하면 우리가 이것을 부정했기 때문입니다:</p> + + <p><code>let myVariable = 3;<br> + !(myVariable === 3);</code></p> + + <p>여기서 테스트하고 있는 것은 "<code>myVariable</code>이 3 과 같지 않은가"입니다. 이것은 <code>false</code>를 반환하는데, <code>myVariable</code>이 3 과 같기 때문입니다.</p> + + <p><code>let myVariable = 3;</code><br> + <code>myVariable !== 3;</code></p> + </td> + </tr> + </tbody> +</table> + +<p>살펴볼 연산자가 더 많이 있지만, 지금은 이것으로 충분합니다. 연산자에 대한 완전한 리스트는 <a href="/ko/docs/Web/JavaScript/Reference/Operators">표현식과 연산자</a>에서 확인해보세요.</p> + +<div class="note"> +<p><strong>참고</strong>: 계산을 수행할 때 자료형이 섞이게 되면 이상한 결과를 불러올 수 있으므로, 변수를 올바르게 참조해 예상하는 결과를 얻을 수 있게 주의해야 합니다. 예를 들어 <code>"35" + "25"</code>를 콘솔에 입력해 보세요. 왜 예상한 결과를 얻을 수 없을까요? 인용부호가 숫자를 문자열로 변경하였고, 숫자를 더하는 대신에 문자열을 붙인 결과를 얻습니다. <code>35 + 25</code>를 입력한다면, 올바른 결과를 얻을 것입니다.</p> +</div> + +<h3 id="조건문">조건문</h3> + +<p>조건문은 어떤 표현식(expression)이 참인지 아닌지를 테스트하고 그 결과에 따라 선택적으로 코드를 실행할 수 있도록 하는 코드 구조입니다. 가장 일반적인 조건문의 형태는 <code>if ... else</code> 문입니다. 예를 들어:</p> + +<pre class="brush: js">let iceCream = 'chocolate'; +if (iceCream === 'chocolate') { + alert('Yay, I love chocolate ice cream!'); +} else { + alert('Awwww, but chocolate is my favorite...'); +}</pre> + +<p><code>if ( ... )</code> 안의 표현식은 테스트입니다 — 여기서는 (위에서 설명한 바와 같이)일치 연산자(identity operator)를 사용하여 변수 <code>iceCream</code>과 문자열 <code>chocolate</code>이 같은지를 비교합니다. 이 비교에서 <code>true</code>가 반환되면 코드의 첫 번째 블록이 실행됩니다. 이 비교가 참(true)가 아닌 경우에는 첫 번째 블록을 건너뛰고 <code>else</code>문 뒤에 있는 두 번째 코드 블록이 대신 실행됩니다.</p> + +<h3 id="함수">함수</h3> + +<p>{{Glossary("Function", "Functions")}}는 재사용하기를 원하는 기능을 담는 방법입니다. 그 절차(재사용 기능)가 필요할 때 매 번 전체 코드를 다시 작성하는 대신 함수의 이름으로 그 함수를 호출할 수 있습니다. 위에서 이미 몇 가지 함수의 사용법을 봤는데, 예를 들면:</p> + +<ol> + <li> + <pre class="brush: js">let myVariable = document.querySelector('h1');</pre> + </li> + <li> + <pre class="brush: js">alert('hello!');</pre> + </li> +</ol> + +<p>이 함수들, <code>document.querySelector</code>와 <code>alert</code>는 언제든지 사용할 수 있게 브라우저에 내장되어 있습니다.</p> + +<p>변수 이름처럼 보이지만 그 뒤에 괄호 — <code>()</code> — 가 있다면 그것은 함수일 것입니다. 함수는 보통 인수({{Glossary("Argument", "arguments")}}) — 함수가 작동하는데 필요한 일련의 데이터 — 를 가집니다. 인수는 괄호 안으로 들어가고, 하나 이상의 인수가 있다면 콤마로 구분됩니다.</p> + +<p>예를 들면, <code>alert()</code> 함수는 브라우저 창에서 팝업창을 만들지만, 그 함수가 그 팝업창에 표시할 문자열을 인자로 주어야 합니다.</p> + +<p>좋은 소식은 여러분 자신만의 함수를 정의할 수 있다는 것입니다 — 다음 예제에서 두 수를 인수로 가지고 그것을 곱하는 간단한 함수를 작성합니다:</p> + +<pre class="brush: js">function multiply(num1,num2) { + let result = num1 * num2; + return result; +}</pre> + +<p>콘솔에서 위 함수를 실행해보고 여러 인수로 테스트해보세요. 가령:</p> + +<pre class="brush: js">multiply(4,7); +multiply(20,20); +multiply(0.5,3);</pre> + +<div class="note"> +<p><strong>참고</strong>: <a href="/ko/docs/Web/JavaScript/Reference/Statements/return"><code>return</code></a> 문은 브라우저에게 함수로부터 나오는 <code>result</code> 변수를 반환하게 함으로써 그 변수를 사용할 수 있게 합니다. 이것은 필수적인 것으로 함수 안에서 정의된 변수는 오직 그 함수 내부에서만 사용 가능하기 때문입니다. 이것을 변수 {{Glossary("Scope", "scoping")}}이라고 합니다. (<a href="/ko/docs/Web/JavaScript/Guide/Values,_variables,_and_literals#Variable_scope">변수 영역에 대한 더 많은 것</a> 을 여기서 읽어보세요.)</p> +</div> + +<h3 id="이벤트">이벤트</h3> + +<p>웹사이트의 실질적인 상호작용에는 이벤트가 필요합니다. 이벤트는 브라우저에서 발생하는 일을 듣고 그에 대한 반응으로 코드를 실행하는 코드 구조입니다. 가장 확실한 예는 마우스로 무언가를 클릭하면 브라우저가 발생시키는 <a href="/ko/docs/Web/Events/click">클릭 이벤트</a>입니다. 이를 시연하려면 콘솔에 다음 코드를 입력한 후 현재 웹페이지를 클릭해보시기 바랍니다:</p> + +<pre class="brush: js">document.querySelector('html').onclick = function() { + alert('Ouch! Stop poking me!'); +}</pre> + +<p>요소에 이벤트를 붙이는 방법은 많습니다. 여기서 HTML 요소를 선택하고 그 요소의 <code><a href="/ko/docs/Web/API/GlobalEventHandlers.onclick">onclick</a></code> 핸들러 프로퍼티에 클릭 이벤트가 실행할 코드를 갖고 있는 익명(anonymous) 함수를 할당합니다.</p> + +<p>유의하세요. 다음은</p> + +<pre class="brush: js">document.querySelector('html').onclick = function() {};</pre> + +<p>다음과 같습니다.</p> + +<pre class="brush: js">let myHTML = document.querySelector('html'); +myHTML.onclick = function() {};</pre> + +<p>단지 짧을 뿐입니다.</p> + +<h2 id="예시_웹사이트_확장하기">예시 웹사이트 확장하기</h2> + +<p>지금까지 자바스크립트의 기본 중 몇 가지를 살펴보았으니 우리가 작성한 예제 사이트에 적용 가능한 몇 가지 멋진 기능을 추가해 봅시다.</p> + +<h3 id="이미지_변경자_추가하기">이미지 변경자 추가하기</h3> + +<p>이 섹션에서는 DOM API 특징을 몇 가지 더 사용해 이미지를 하나 더 추가하고, 이미지가 클릭될 때 자바스크립트를 이용해 두 이미지 사이에 전환이 이루어지도록 해보겠습니다.</p> + +<ol> + <li>맨 먼저, 사이트에 나타내길 원하는 다른 이미지를 찾으세요. 처음 이미지와 같은 사이즈 또는 가능하면 비슷한 크기여야 합니다.</li> + <li><code>images</code> 폴더에 이미지를 저장하세요.</li> + <li>이미지 이름을 'firefox2.png'(인용부호 없이)로 바꾸세요.</li> + <li><code>main.js</code> 파일로 가서, 다음 자바스크립트를 입력하세요 (만약 "Hello world" 자바스크립트가 있다면, 지우세요): + <pre class="brush: js">let myImage = document.querySelector('img'); + +myImage.onclick = function() { + let mySrc = myImage.getAttribute('src'); + if(mySrc === 'images/firefox-icon.png') { + myImage.setAttribute ('src','images/firefox2.png'); + } else { + myImage.setAttribute ('src','images/firefox-icon.png'); + } +}</pre> + </li> + <li>모든 파일을 저장하고 브라우저에서 <code>index.html</code>을 불러오세요. 이제 여러분이 이미지를 클릭할 때 이미지가 다른 이미지로 바뀔 것입니다!</li> +</ol> + +<p><code>myImage</code> 변수에 {{htmlelement("image")}} 요소에 대한 참조를 저장합니다. 다음으로 이 변수의 <code>onclick</code> 이벤트 핸들러 프로퍼티에 이름이 없는 함수("익명" 함수)를 할당합니다. 이제, 매번 이미지 요소가 클릭될 때:</p> + +<ol> + <li>이미지의 <code>src</code> 속성 값을 얻습니다.</li> + <li><code>src</code> 값이 원래 이미지 경로와 같은지 확인하기 위해 조건문을 사용합니다: + <ol> + <li>만약 같다면, <code>src</code> 값을 두 번째 이미지 경로로 변경하여 다른 이미지가 {{htmlelement("image")}} 요소 안에 로드되도록 합니다.</li> + <li>같지 않다면(이미 변경되었다는 것을 의미), 원래 상태로 되돌리기 위해 <code>src</code> 값을 원래 이미지 경로 바꿔 놓습니다.</li> + </ol> + </li> +</ol> + +<h3 id="개인화된_환영_메시지_추가하기">개인화된 환영 메시지 추가하기</h3> + +<p>다음으로는 다른 코드를 약간 추가할 것인데, 이 코드는 사용자가 처음으로 사이트에 방문했을 때 페이지의 제목을 개인화된 환영 메시지로 바꾸는 것입니다. 이 환영 메시지는 해당 사용자가 사이트를 떠났다가 돌아오더라도 계속 유지될 것입니다 — 이 메시지를 <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API">웹 저장소 API(Web Storage API)</a>를 이용해 저장할 것입니다. 사용자를 변경할 수 있는 옵션도 추가하여 언제든지 필요할 때 환영 메시지를 나타나도록 할 것입니다.</p> + +<ol> + <li><code>index.html</code> 내의 {{htmlelement("script")}} 요소 바로 앞에 다음 줄을 추가하세요: + + <pre class="brush: html"><button>Change user</button></pre> + </li> + <li><code>main.js</code> 파일의 맨 마지막에 다음 두 줄을 똑같이 추가하세요 — 이 코드는 새로 추가된 버튼과 본문 제목에 대한 참조를 가져와 변수에 저장하는 것입니다: + <pre class="brush: js">let myButton = document.querySelector('button'); +let myHeading = document.querySelector('h1');</pre> + </li> + <li>다음으로 개인화된 인삿말을 설정하기 위해 다음 함수를 추가합니다 — 아직 아무 동작도 하지않지만 좀 이따가 고칠겁니다: + <pre class="brush: js">function setUserName() { + let myName = prompt('Please enter your name.'); + localStorage.setItem('name', myName); + myHeading.textContent = 'Mozilla is cool, ' + myName; +}</pre> + 이 함수는 <code>alert()</code>와 약간 닮은 대화상자를 불러오는 <code><a href="/ko/docs/Web/API/Window.prompt">prompt()</a> </code>함수를 포함하고 있습니다. <code>prompt()</code>는 사용자에게 어떤 데이터를 입력하길 요청하고, 사용자가<code> </code><em>OK </em>를 누른 후에 그 값을 변수에 저장합니다. 이 예시에서는, 사용자에게 그들의 이름을 입력하길 요청하고 있습니다. 다음으로, 브라우저에 데이터를 저장하고 나중에 불러올 수 있도록 해주는 <code>localStorage</code>라는 API 를 부릅니다. 우리는 <code>'name'</code> 라는 데이터 항목을 생성하고 저장하기 위해 localStorage 의 <code>setItem()</code>함수를 사용합니다. 그리고 사용자가 입력한 이름을 포함하는 그 값을 <code>myName</code> 변수에 저장합니다. 마지막으로, 헤딩의 <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">textContent</span></font>를 유저의 이름을 포함한 스트링으로 설정합니다.</li> + <li>다음으로, 이 <code>if ... else</code> 문을 추가합니다 — 처음 불려질 때 앱이 셋업되도록 이 초기화 코드를 불러옵니다: + <pre class="brush: js">if(!localStorage.getItem('name')) { + setUserName(); +} else { + let storedName = localStorage.getItem('name'); + myHeading.textContent = 'Mozilla is cool, ' + storedName; +}</pre> + 이 구문은 먼저 <code>name </code>데이터 아이템이 존재하는지 확인하기 위해 부정 연산자 (논리적 NOT, !로 표현되는) 를 사용합니다. 존재하지 않는다면 값을 생성하기 위해 <code>setUserName()</code> 함수를 실행합니다. 존재한다면 (예로, 이전 방문을 통해 사용자가 세팅되었음), 우리는 <code>getItem() </code>을 사용해 저장된 이름 값을 얻고, 헤딩의 <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">textContent</span></font> 을 <code>setUserName()</code> 안에서 작업한 것과 같은 사용자의 이름을 포함한 문자열로 세팅합니다.</li> + <li>마지막으로, 아래의 <code>onclick</code> 이벤트 핸들러를 버튼에 추가해서, 클릭될 때 <code>setUserName()</code> 함수가 실행되도록 합니다. 이것은 버튼을 누름으로 인해 유저가 원하는 새 이름을 설정할 수 있도록 해줍니다. + <pre class="brush: js">myButton.onclick = function() { + setUserName(); +} +</pre> + </li> +</ol> + +<p>이제 여러분이 사이트에 처음으로 방문했을 때, 개인화된 메시지를 제공하기 위해 여러분의 이름을 물을 것입니다. 그리고 언제든 버튼을 누름으로 여러분이 원하는 이름으로 변경할 수 있습니다. 추가 선물로써, 이름은 <code>localStorage</code> 에 저장되기 때문에, 사이트가 닫힌 이후에도 이름이 유지됩니다. 그래서 개인화된 메시지는 여러분이 사이트를 다시 열었을 때 그대로 남아있을 것입니다!</p> + +<h3 id="사용자_이름이_null">사용자 이름이 null?</h3> + +<p>예제를 실행 시키고 바로 나타나는 다이얼로그 상자에 당신의 이름을 입력하고<em>Cancel</em> 버튼을 눌러보세요. "Mozilla is cool, null"라는 제목을 보게될 것입니다. 이것은 사용자가 입력을 취소했을 때 값이, 원래 Javascript가 값이 없음을 표현하는 특별한 값인 <code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/null">null</a></code>로 설정되기 때문입니다.</p> + +<p>또한, 어떠한 이름도 기입하지 않고 OK를 눌러보세요. — 꽤 분명한 이유로 "Mozilla is cool,"라는 제목을 보게될 것입니다.</p> + +<p>이러한 문제들을 피하고 싶다면, <code>setUserName()</code> 함수를 수정함으로써 사용자가 null 또는 공백 이름을 입력하지 않았는지 체크해야 합니다. 이와 같이:</p> + +<pre class="brush: js">function setUserName() { + let myName = prompt('Please enter your name.'); + if(!myName || myName === null) { + setUserName(); + } else { + localStorage.setItem('name', myName); + myHeading.innerHTML = 'Mozilla is cool, ' + myName; + } +}</pre> + +<p>해석하자면 — <code>myName</code>에 할당된 값이 없거나 null일 때, <code>setUserName()</code>함수를 처음부터 다시 실행합니다. 값이 있으면(위의 if 조건이 not true일 때) <code>localStorage</code>에 값을 저장하고 헤딩의 텍스트에 값을 설정합니다.</p> + +<h2 id="마무리">마무리</h2> + +<p>이 글의 모든 설명을 따라오셨다면, 이와 같이 보이는 페이지가 되실 겁니다. (<a class="external-icon external" href="https://mdn.github.io/beginner-html-site-scripted/">여기서</a> 확인하실 수도 있습니다):</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/9539/website-screen-scripted.png" style="display: block; height: 995px; margin: 0px auto; width: 800px;"></p> + +<p>혹시 막히셨다면, 여러분의 코드와 Github에 있는 우리의 <a class="external external-icon" href="https://github.com/mdn/beginner-html-site-scripted/blob/gh-pages/scripts/main.js">예제 코드</a>와 항상 비교해보세요.</p> + +<p>여기서, 우리는 자바스크립트의 겉을 살짝 맛봤습니다. 즐겁게 배우셨고, 더 깊게 학습하고 싶으시다면, <a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript">JavaScript 안내서</a> 페이지로 가보세요.</p> + +<p>{{PreviousNext("Learn/Getting_started_with_the_web/CSS_basics", "Learn/Getting_started_with_the_web/Publishing_your_website")}}</p> diff --git a/files/ko/learn/getting_started_with_the_web/what_will_your_website_look_like/index.html b/files/ko/learn/getting_started_with_the_web/what_will_your_website_look_like/index.html new file mode 100644 index 0000000000..a311b1912f --- /dev/null +++ b/files/ko/learn/getting_started_with_the_web/what_will_your_website_look_like/index.html @@ -0,0 +1,95 @@ +--- +title: 웹사이트의 외관은 어떻게 할까요? +slug: Learn/Getting_started_with_the_web/What_will_your_website_look_like +tags: + - Beginner + - Learn + - 'l10n:priority' +translation_of: Learn/Getting_started_with_the_web/What_will_your_website_look_like +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Getting_started_with_the_web/Installing_basic_software", "Learn/Getting_started_with_the_web/Dealing_with_files", "Learn/Getting_started_with_the_web")}}</div> + +<div class="summary"> +<p><em>웹사이트의 외관은 어떻게 할까요?</em> 에서는 "나의 웹사이트가 무슨 정보를 제공할 것인지?" "무슨 글꼴과 색상을 사용할 것인지?" "나의 웹사이트가 무엇을 하는지?" 를 포함해, 코드를 작성하기 <em>전에 </em>여러분이 해야할 계획 세우기와 디자인에 대해 이야기 할 것입니다.</p> +</div> + +<h2 id="중요한것_먼저_하기_계획_세우기">중요한것 먼저 하기: 계획 세우기</h2> + +<p>무언가를 하기 전에, 여러분은 어떤 아이디어가 필요합니다. 웹사이트가 실제로 무엇을 해야하는지? 웹사이트가 기본적으로 무엇을 할 수 있는지, 하지만 여러분의 첫 시도를 위해선 이것을 간단히 할 필요가 있습니다. 우리는 제목과 사진, 그리고 몇 개의 문단을 포함한 간단한 웹페이지를 제작하는 것부터 시작할 것입니다.</p> + +<p>시작하기 위해, 여러분은 몇 가지 질문에 답해야 합니다.</p> + +<ol> + <li><strong>여러분의 웹사이트는 무엇에 관한 것인가요? </strong>강아지나 뉴욕, 또는 팩맨 좋아하세요?</li> + <li><strong>주제에 대해 어떤 정보를 나타낼 것인가요? </strong>여러분의 웹페이지에 나타내기 원하는 제목과 몇개의 문단들, 그리고 그림에 대한 생각을 작성하세요.</li> + <li><strong>웹사이트의 외관은 어떻게 할까요, </strong>in simple high-level terms. 배경색은 무엇으로 할 것인지?어떤 글꼴(폰트)이 적합한지: 딱딱하게, 만화스럽게, 굵고 크게, 얇게?</li> +</ol> + +<div class="note"> +<p><strong>참고</strong>: 복잡한 프로젝트들은 색상, 글꼴, 페이지의 항목간 공간, 적절한 문체 등 세부적인 가이드라인을 필요로 합니다. 이것은 디자인 가이드 또는 브랜드 북이라고 불리기도 합니다. <a href="https://www.mozilla.org/en-US/styleguide/products/firefox-os/">파이어폭스 OS 가이드라인</a><em>에서 그 예시를 볼 수 있습니다.</em>.</p> +</div> + +<h2 id="디자인을_스케치하기">디자인을 스케치하기</h2> + +<p>다음으로, 펜과 종이를 가져와 여러분의 사이트가 어떻게 나타날 것인지 대략적으로 스케치하세요. 여러분의 첫 번째 간단한 웹페이지를 위해선, 과도한 스케치는 필요 없지만, 지금 습관으로 만드는게 좋습니다. 정말 도움이 됩니다--반 고흐가 될 필요는 없습니다!</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/9239/website-drawing-scan.png" style="display: block; height: 460px; margin: 0px auto; width: 640px;"></p> + +<div class="note"> +<p><strong>노트</strong>: 실제로도, 복잡한 웹사이트들에서, 디자인팀은 보통 종이에 대략적인 스케치를 하는 것으로 일을 시작합니다. 그리고 이후에 시각적인 편집기나 웹 기술을 사용해 디지털 모형화 합니다.</p> + +<p>웹 팀들은 그래픽 디자이너와 사용자 경험 (UX) 디자이너 모두와 일합니다. 그래픽 디자이너들은, 분명히, 웹사이트의 시각적인 것들을 합칩니다. UX 디자이너는 사용자들이 웹사이트를 어떻게 경험하고 반응하는지에 대한 무언가 더 추상적인 것을 합니다.</p> +</div> + +<h2 id="자원_선택하기">자원 선택하기</h2> + +<p>여기에서, 여러분의 웹페이지에 최종적으로 나타나게될 내용을 합치는 것을 시작하기에 좋습니다.</p> + +<h3 id="문자">문자</h3> + +<p>여러분은 제목이나 문단들을 일찍 작성해야 합니다. 항상 신경쓰는것이 좋습니다.</p> + +<h3 id="주요_색상">주요 색상</h3> + +<p>색상을 선택하기 위해, <a href="https://developer.mozilla.org/ko/docs/Web/CSS/CSS_Colors/Color_picker_tool">the Color Picker</a>로 가서 여러분이 원하는 색을 찾아보세요. 한 색을 선택하면, 여러분은 #660066같은 여섯 문자의 이상한 코드를 보게 될 것입니다. 이것은 <em>hex(adecimal) </em>코드로 불리고, 여러분의 색을 나타냅니다. 안전한 어느 곳에 복사해두세요.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/8975/Screenshot%20from%202014-11-03%2017:40:49.png" style="height: 262px; width: 448px;"></p> + +<h3 id="그림들">그림들</h3> + +<p>그림을 선택하기 위해, <a href="https://www.google.com/imghp?gws_rd=ssl">Google Images</a>에 가서 적합한 것을 찾아보세요.</p> + +<ol> + <li>원하는 그림을 찾으면, 이미지를 클릭하세요.</li> + <li><em>이미지 보기(View image)</em>버튼을 누르세요.</li> + <li>다음 페이지에서, 이미지를 우클릭하고 (맥에서는 Ctrl + click), <em>다른 이름으로 이미지 저장(Save Image As...)</em>를 누르고, 이미지를 저장할 안전한 공간을 선택하세요. 다른 방법으로는, 나중에 사용하기 위해 여러분의 웹 브라우저의 주소에서 이미지의 웹 주소를 복사하는 것이 있습니다.</li> +</ol> + +<p><img alt="" src="https://mdn.mozillademos.org/files/8985/Screenshot%20from%202014-11-04%2015:09:21.png" style="height: 293px; width: 420px;"></p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/8989/Screenshot%20from%202014-11-04%2015:20:48.png" style="height: 292px; width: 340px;"></p> + +<div class="note"> +<p><strong>노트</strong>: Google Images를 포함한, 웹에 있는 대부분의 그림들은 저작권이 있습니다. 저작권 침해의 가능성을 줄이기 위해선, Google's license filter를 사용하는 방법이 있습니다. 1) 검색 도구(<strong>Search tools)</strong>를 클릭하고, 2) 사용 권한(<strong>Usage rights)</strong>를 선택하면 됩니다:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/8981/Screenshot%20from%202014-11-04%2014:27:45.png" style="height: 195px; width: 587px;"></p> +</div> + +<h3 id="글꼴">글꼴</h3> + +<p>글꼴을 선택하기 위해:</p> + +<ol> + <li><a href="http://www.google.com/fonts">Google Fonts</a>에 가서 원하는 것을 찾을 때까지 스크롤을 내리세요. 결과에 대한 필터를 위해선 왼쪽 메뉴를 사용하면 됩니다.</li> + <li>원하는 폰트의 옆에 있는 <em>Add to collection</em> 버튼을 클릭하세요.</li> + <li>페이지의 아래에 있는 <em>Use</em> 버튼을 클릭하세요.</li> + <li>다음 페이지에서, 3 과 4 구역으로 스크롤을 내리고, 구글에서 제공한 코드를 여러분의 텍스트 편집기에 복사하고 나중을 위해 저장하세요.</li> +</ol> + +<p><img alt="" src="https://mdn.mozillademos.org/files/8991/Screenshot%20from%202014-11-04%2015:38:14.png" style="height: 282px; width: 525px;"></p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/8993/Screenshot%20from%202014-11-04%2015:51:36.png" style="height: 379px; width: 530px;"></p> + +<p>{{PreviousMenuNext("Learn/Getting_started_with_the_web/Installing_basic_software", "Learn/Getting_started_with_the_web/Dealing_with_files", "Learn/Getting_started_with_the_web")}}</p> diff --git a/files/ko/learn/getting_started_with_the_web/기본_소프트웨어_설치하기/index.html b/files/ko/learn/getting_started_with_the_web/기본_소프트웨어_설치하기/index.html new file mode 100644 index 0000000000..58ec16a8d9 --- /dev/null +++ b/files/ko/learn/getting_started_with_the_web/기본_소프트웨어_설치하기/index.html @@ -0,0 +1,75 @@ +--- +title: 기본 소프트웨어 설치하기 +slug: Learn/Getting_started_with_the_web/기본_소프트웨어_설치하기 +tags: + - Beginner + - Browser + - Learn + - Setup + - Tools + - WebMechanics + - 'l10n:priority' +translation_of: Learn/Getting_started_with_the_web/Installing_basic_software +--- +<div>{{LearnSidebar}}</div> + +<div>{{NextMenu("Learn/Getting_started_with_the_web/What_will_your_website_look_like", "Learn/Getting_started_with_the_web")}}</div> + +<div class="summary"> +<p>기본 소프트웨어 설치하기에서는 간단한 웹 개발을 하기 위해 어떤 도구가 필요하고, 어떻게 설치할 수 있는지 보여드립니다.</p> +</div> + +<h2 id="전문가들이_사용하는_도구는_뭔가요">전문가들이 사용하는 도구는 뭔가요?</h2> + +<ul> + <li><strong>컴퓨터</strong>. 당연한 얘기로 들리겠지만, 여러분 중 누군가는 이 글을 휴대폰이나 도서관의 컴퓨터로 읽고 계실겁니다. 진지한 웹 개발을 위해서는 데스크탑 컴퓨터(윈도우, 맥, 또는 리눅스)에 투자하는것이 좋습니다.</li> + <li>코드 작성을 위한 <strong>텍스트 편집기</strong>. 순수 텍스트 편집기(<a href="https://www.sublimetext.com/">Sublime</a>, <a href="http://brackets.io/">Brackets</a>, <a href="https://atom.io/">Atom</a>, <a href="https://code.visualstudio.com/">Visual Studio Code</a> 등) 또는 하이브리드 편집기(<a href="https://www.adobe.com/products/dreamweaver.html">Dreamweaver</a>, <a href="https://www.jetbrains.com/webstorm/">WebStorm</a> 등)를 사용하시면 됩니다. 사무용 문서 편집기는 웹 브라우저의 렌더링 엔진을 방해하는 숨겨진 요소를 사용하기 때문에 코드 작성 용도로는 적합하지 않습니다.</li> + <li>코드를 테스트하기 위한 <strong>웹 브라우저</strong>. 현재 가장 널리 사용되는 브라우저로는 <a href="https://www.mozilla.org/ko/firefox/new/">Firefox</a>, <a href="https://www.google.com/chrome/browser/">Chrome</a>, <a href="http://www.opera.com/">Opera</a>, <a href="https://www.apple.com/kr/safari/">Safari</a>, <a href="https://support.microsoft.com/ko-kr/help/17621/internet-explorer-downloads">Internet Explorer</a>, 그리고 <a href="https://www.microsoft.com/ko-kr/windows/microsoft-edge">Microsoft Edge</a>가 있습니다. 또, 여러분의 웹 사이트가 휴대용 장치와 오래된 브라우저(IE 8~10 등)에서는 어떻게 동작하는지도 시험해보셔야 합니다.</li> + <li>웹 페이지를 위한 이미지를 만들 수 있는 <strong>이미지 편집기.</strong> <a href="http://www.gimp.org/">GIMP</a>, <a href="http://www.getpaint.net/">Paint.NET</a>, <a href="https://www.adobe.com/kr/products/photoshop.html">Photoshop</a> 등이 있습니다.</li> + <li>서버 파일 관리, 프로젝트 협업, 코드와 자원 공유, 수정 충돌 방지를 위한 <strong>버전 관리 시스템</strong>. 지금은 <a href="http://git-scm.com/">Git</a>이 제일 대중적인 버전 관리 시스템이며 Git 기반의 코드 공유 서비스인 <a href="https://github.com/">GitHub</a>도 매우 유명합니다.</li> + <li>오래 된 웹 호스팅 계정에 파일을 올리기 위한 <strong>FTP 프로그램</strong>. 지금은 점점 Git이 FTP를 대체하고 있습니다. (S)FTP 프로그램은 <a href="https://cyberduck.io/">Cyberduck</a>, <a href="https://fetchsoftworks.com/">Fetch</a>, <a href="https://filezilla-project.org/">FileZilla</a> 외에도 무수히 많습니다.</li> + <li>코드 압축과 테스트 등 반복 작업을 자동으로 수행하기 위한 <strong>자동화 시스템</strong>. <a href="http://gruntjs.com/">Grunt</a>나 <a href="http://gulpjs.com/">Gulp</a> 등이 있습니다.</li> + <li>흔히 쓰이는 기능의 코드 작성 속도를 높히기 위한 템플릿, 라이브러리, 프레임워크, 기타 등등.</li> + <li>이 밖에도 더 많은 도구들을 써요!</li> +</ul> + +<h2 id="지금_당장_필요한_도구는_뭔가요">지금 당장 필요한 도구는 뭔가요?</h2> + +<p>전문가가 사용하는 리스트가 두렵게 다가올지도 모르지만, 다행히도 여러분은 저런 대부분의 것들을 모르더라도 웹 개발을 시작하실 수 있습니다. 이 글을 통해 여러분이 최소한의 도구(텍스트 편집기와 최신 웹 브라우저 같은)를 마련할 수 있도록 할 것입니다.</p> + +<h3 id="텍스트_편집기_설치하기">텍스트 편집기 설치하기</h3> + +<p>지금도 기본적인 텍스트 편집기는 아마 갖고 계실겁니다. Windows는 기본으로 <a href="https://ko.wikipedia.org/wiki/%EB%A9%94%EB%AA%A8%EC%9E%A5_(%EC%86%8C%ED%94%84%ED%8A%B8%EC%9B%A8%EC%96%B4)">메모장</a>을, macOS는 <a href="https://en.wikipedia.org/wiki/TextEdit">TextEdit</a>을 포함하고 있습니다. Linux는 배포판마다 다르지만, Ubuntu는 <a href="https://ko.wikipedia.org/wiki/Gedit">gedit</a>을 가지고 있습니다.</p> + +<p>웹 개발을 위해서라면 메모장이나 TextEdit보다는 좋은걸 써야 할겁니다. <a href="http://brackets.io/">Brackets</a>를 추천드립니다. 무려 무료인데다가(쫭쫭) 실시간 미리보기와 코드 힌트도 제공하기 때문이에요!</p> + +<h3 id="최신_웹_브라우저_설치하기">최신 웹 브라우저 설치하기</h3> + +<p>이제, 코드를 테스트할 데스크탑 웹 브라우저를 몇 가지 설치할겁니다. 다음 목록에서 여러분의 운영체제를 고른 후 원하시는 브라우저의 링크로 들어가 설치하세요.</p> + +<ul> + <li>Linux: <a href="https://www.mozilla.org/ko/firefox/new/">Firefox</a>, <a href="https://www.google.com/chrome/browser/">Chrome</a>, <a href="http://www.opera.com/">Opera</a>.</li> + <li>Windows: <a href="https://www.mozilla.org/ko/firefox/new/">Firefox</a>, <a href="https://www.google.com/chrome/browser/">Chrome</a>, <a href="http://www.opera.com/">Opera</a>, <a href="https://support.microsoft.com/ko-kr/help/17621/internet-explorer-downloads">Internet Explorer</a>, <a href="https://www.microsoft.com/ko-kr/windows/microsoft-edge">Microsoft Edge</a> (Window 10은 Edge를 탑재하고 있습니다. Windows 7 이상에선 Internet Explorer 11을 설치할 수 있습니다. 이외에는 다른 브라우저를 설치해야 합니다)</li> + <li>Mac: <a href="https://www.mozilla.org/ko/firefox/new/">Firefox</a>, <a href="https://www.google.com/chrome/browser/">Chrome</a>, <a href="http://www.opera.com/">Opera</a>, <a href="https://www.apple.com/kr/safari/">Safari</a> (Safari는 iOS와 macOS에 탑재되어 있습니다)</li> +</ul> + +<p>다음으로 진행하기 전에, 테스트를 위해 최소 두 개 이상의 브라우저를 설치해야 합니다.</p> + +<h3 id="로컬_웹_서버_설치하기">로컬 웹 서버 설치하기</h3> + +<p>어떤 예제는 제대로 작동하려면 웹 서버가 필요합니다. <a href="https://developer.mozilla.org/ko/docs/Learn/Common_questions/set_up_a_local_testing_server">로컬 테스트 서버 설치하기</a>에서 설치하는 방법을 알아보세요!</p> + +<p>{{NextMenu("Learn/Getting_started_with_the_web/What_will_your_website_look_like", "Learn/Getting_started_with_the_web")}}</p> + +<h2 id="이번_과정에서는">이번 과정에서는</h2> + +<ul> + <li id="Installing_basic_software"><a href="/ko/docs/Learn/Getting_started_with_the_web/%EA%B8%B0%EB%B3%B8_%EC%86%8C%ED%94%84%ED%8A%B8%EC%9B%A8%EC%96%B4_%EC%84%A4%EC%B9%98%ED%95%98%EA%B8%B0">기본 소프트웨어 설치하기</a></li> + <li id="What_will_your_website_look_like"><a href="/ko/docs/Learn/Getting_started_with_the_web/What_will_your_website_look_like">What will your website look like?</a></li> + <li id="Dealing_with_files"><a href="/ko/docs/Learn/Getting_started_with_the_web/Dealing_with_files">Dealing with files</a></li> + <li id="HTML_basics"><a href="/ko/docs/Learn/Getting_started_with_the_web/HTML_basics">HTML basics</a></li> + <li id="CSS_basics"><a href="/ko/docs/Learn/Getting_started_with_the_web/CSS_basics">CSS basics</a></li> + <li id="JavaScript_basics"><a href="/ko/docs/Learn/Getting_started_with_the_web/JavaScript_basics">JavaScript basics</a></li> + <li id="Publishing_your_website"><a href="/ko/docs/Learn/Getting_started_with_the_web/Publishing_your_website">Publishing your website</a></li> + <li id="How_the_web_works"><a href="/ko/docs/Learn/Getting_started_with_the_web/How_the_Web_works">How the web works</a></li> +</ul> diff --git a/files/ko/learn/getting_started_with_the_web/웹사이트_출판하기/index.html b/files/ko/learn/getting_started_with_the_web/웹사이트_출판하기/index.html new file mode 100644 index 0000000000..df2016e530 --- /dev/null +++ b/files/ko/learn/getting_started_with_the_web/웹사이트_출판하기/index.html @@ -0,0 +1,176 @@ +--- +title: 웹사이트 출판하기 +slug: Learn/Getting_started_with_the_web/웹사이트_출판하기 +translation_of: Learn/Getting_started_with_the_web/Publishing_your_website +--- +<p>{{LearnSidebar}}</p> + +<p>{{PreviousMenuNext("Learn/Getting_started_with_the_web/JavaScript_basics", "Learn/Getting_started_with_the_web/How_the_Web_works", "Learn/Getting_started_with_the_web")}}</p> + +<div class="summary"> +<p>일단 여러분의 웹사이트를 만들기 위한 코드 작성과 파일 구성을 끝내셨다면, 이 모든 것을 온라인에 올려 사람들이 찾을 수 있게 할 필요가 있습니다. 이 글은 어떻게 최소한의 노력으로 간단한 예시 코드를 온라인에서 얻을 수 있는지 보여줍니다.</p> +</div> + +<h2 id="옵션들은_뭐가_있나요">옵션들은 뭐가 있나요?</h2> + +<p>웹사이트를 출판하는 것은 간단한 것이 아닙니다, 주된 이유는 이것에 아주 많은 다른 방법이 있다는 것입니다. 이 글에서는 모든 가능한 방법을 문서화 하는 것이 목적이 아닙니다. 대신에, 초심자의 관점에서 세가지 큰 전략에 대한 장단점에 대해 이야기 할 것입니다, 그리고나서 현재로써 적합할 하나의 방법을 보여드릴 것입니다.</p> + +<h3 id="호스팅과_도메인_이름_얻기">호스팅과 도메인 이름 얻기</h3> + +<p>만약 여러분이 출판된 웹사이트에 대한 모든 컨트롤를 원한다면, 이것들을 구매해야 할 것입니다:</p> + +<ul> + <li>호스팅 — 호스팅 회사의<a href="/en-US/Learn/What_is_a_web_server"> 웹 서버</a> 에서 빌린 파일 공간. 이 공간에 여러분의 웹사이트 파일을 놓을 것입니다, 그리고 웹 서버는 컨텐트를 요청하는 웹 유저에게 그 컨텐트를 제공합니다.</li> + <li><a href="/en-US/Learn/Understanding_domain_names">도메인 이름</a> — <code>http://www.mozilla.org</code>, <code>또는 http://www.bbc.co.uk</code> 같이, 사람들이 여러분의 웹사이트를 찾을 수 있는 특정 주소. <strong>도메인 등록 기관</strong>으로부터 몇 년간 사용할 수 있는 여러분의 도메인을 빌리세요.</li> +</ul> + +<p>많은 전문적인 웹사이트들은 이 방법으로 온라인에 진출합니다.</p> + +<p>게다가, 여러분은 서버로 웹사이트 파일들을 실제로 전송하기 위한 파일 전송 프로토콜 (FTP) 프로그램 (자세한 내용은 <a href="/en-US/Learn/How_much_does_it_cost#Software">얼마나 드나요: 소프트웨어</a> 에서 확인하세요) 이 필요할 것입니다. FTP 프로그램은 아주 다양합니다, 하지만 일반적으로 호스팅 회사에 의해 제공된 정보 (예로 사용자 이름, 비밀번호, 호스트 이름) 를 사용해 여러분의 웹서버에 로그인을 해야 합니다. 그러면 프로그램은 여러분의 로컬 파일들과 웹 서버의 파일을 두 창에서 보여주므로, 그것들을 외부로 전송하거나 다시 돌려 놓을 수 있습니다:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/9469/ftp.jpg" style="display: block; height: 487px; margin: 0px auto; width: 800px;"></p> + +<h4 id="호스팅과_도메인을_찾는_팁">호스팅과 도메인을 찾는 팁</h4> + +<ul> + <li>저희는 여기서 상업적인 호스팅 회사를 홍보하는 것이 아닙니다. 호스팅 회사와 도메인 이름 등록 기관을 찾기 위해서는, 일단 "웹 호스팅" 과 도메인 이름 등록을 팔고있는 회사를 찾기 위한 "도메인 이름" 을 위한 검색을 하세요. 이러한 모든 회사들은 여러분이 원하는 도메인이름을 위한 검색에 있어 특징을 갖고 있을 것입니다.</li> + <li>여러분의 집이나 사무실 인터넷 서비스 공급자는 작은 웹사이트를 위한 어떤 제한된 호스팅을 공급할지도 모릅니다. 가능한 특징들은 제한적일 것이지만, 여러분의 첫 번째 시도를 위해서는 완벽할 것 같습니다 — 그들에게 연락해 요청하세요!</li> + <li><a href="https://neocities.org/">Neocities</a>, <a href="https://www.blogger.com">Blogspot</a>, 그리고 <a href="https://wordpress.com/">Wordpress</a> 같은 몇 개의 무료로 이용가능한 서비스가 있습니다. 다시 말해, 여러분이 지불한 만큼 얻을 수 있지만, 이것들은 여러분의 첫 시도를 위해선 완벽합니다. 무료 서비스들은 대부분 업로드를 위한 FTP 소프트웨어도 요구하지 않습니다 — 그들의 웹 인터페이스에 그냥 끌어다 놓으면 됩니다.</li> + <li>어떤 회사들은 하나의 패키지에 호스팅과 도메인 모두를 제공하기도 합니다.</li> +</ul> + +<h3 id="GitHub_또는_Dropbox_같은_온라인_도구_사용하기">GitHub 또는 Dropbox 같은 온라인 도구 사용하기</h3> + +<p>어떤 도구들은 여러분이 여러분의 웹사이트를 온라인에 출판할 수 있게 해줍니다:</p> + +<ul> + <li><a href="https://github.com/">GitHub</a> 은 "소셜 코딩" 사이트입니다. 여러분이 <a href="http://git-scm.com/">Git</a> <strong>버전 관리 시스템</strong> 안에 저장을 위한 코드 저장소를 업로드하게 해줍니다.<strong> </strong>코드 프로젝트에서 협업할 수 있고, 기본적으로 시스템은 오픈 소스가 됩니다, 이 것은 세상의 누구든 여러분의 GitHub 코드를 찾아볼 수 있다는 말입니다, 사용하세요, 이것으로부터 배우세요, 그리고 개선하세요. 여러분으 다른 사람들의 코드에도 마찬가지로 작업 할 수 있습니다! 이건 참여하기에 아주 중요하고 유용한 커뮤니티입니다, 그리고 Git/GitHub 은 아주 유명한 <a href="http://git-scm.com/book/en/v2/Getting-Started-About-Version-Control">버전 관리 시스템</a> 입니다 — 대부분의 기술 회사들은 현재 이것을 그들의 작업흐름에서 사용하고 있습니다. GitHub 은 웹에서 존재하는 웹사이트 코드를 전시할 수 있도록 해주는 <a href="https://pages.github.com/">GitHub pages</a> 라는 아주 유용한 특징을 갖습니다.</li> + <li><a href="https://www.dropbox.com/">Dropbox</a> 는 웹에 여러분의 파일들을 저장하고 어떤 컴퓨터에서든 사용가능하게 해주는 파일 저장 시스템입니다. 인터넷 접속이 되는 누구든 여러분이 공개적으로 접근가능하게 해둔 Dropbox 폴더에 접근할 수 있습니다. 만약 그 폴더가 웹사이트 파일을 포함한다면, 자동적으로 웹사이트로써 제공될 것입니다. 더 많은 정보는 <a href="http://www.dropboxwiki.com/tips-and-tricks/host-websites-with-dropbox">Dropbox 로 웹사이트 관리하기</a> 를 확인하세요.</li> +</ul> + +<p>대부분의 호스팅과 다르게, 많은 도구들은 일반적으로 무료이지만, 여러분은 제한된 기능들만 사용할 수 있습니다.</p> + +<h3 id="Thimble_같은_웹-기반_IDE_사용하기">Thimble 같은 웹-기반 IDE 사용하기</h3> + +<p>HTML, CSS 그리고 JavaScript 를 입력할 수 있게 하고 웹사이트로 만들어 질 때 코드의 결과를 보여주는 웹사이트 개발 환경을 대행하는 웹 앱은 많습니다 — 모든것이 한 브라우저 탭 안에 있습니다! 일반적으로 이러한 도구들을 이야기하기는 매우 쉽고, 배우기에 최고이고, 무료이고 (기본적 기능에대해), 그들은 여러분의 특정 웹 주소에 있는 만들어진 페이지를 관리합니다. 하지만, 그 기본적인 기능들은 매우 한정적이고, 그 앱들은 보통 자원들 (이미지 같은) 을 위한 관리 공간을 제공하지 않습니다.</p> + +<p>여기 몇 개의 예시들을 실행해보시고, 어떤것이 제일 좋은지 확인해보세요:</p> + +<ul> + <li><a href="https://jsfiddle.net/">JSFiddle</a></li> + <li><a href="https://thimble.webmaker.org/">Thimble</a></li> + <li><a href="http://jsbin.com/">JSBin</a></li> +</ul> + +<p><img alt="" src="https://mdn.mozillademos.org/files/9471/jsbin-screen.png" style="display: block; height: 849px; margin: 0px auto; width: 1392px;"></p> + +<h2 id="GitHub_를_통한_출판">GitHub 를 통한 출판</h2> + +<p>이제 어떻게 GitHub 페이지를 통해 여러분의 사이트를 출판할 수 있는지 알아보도록 합시다. 이게 여러분의 사이트를 출판하는데 유일한 방법이거나 최고의 방법이라고 이야기 하지는 않을 것입니다, 하지만 이것은 무료이고, 꽤 간단하고, 앞으로 유용할 여러분이 알게 될 몇 가지 새로운 기술도 다룰 것입니다.</p> + +<h3 id="기본_설치">기본 설치</h3> + +<ol> + <li>먼저, 여러분의 장치에 <a href="http://git-scm.com/downloads">Git 을 설치</a> 하세요. 이것은 GitHub 이 위에서 작동하게 되는 기초가 되는 버전 컨트롤 시스템 소프트웨어 입니다.</li> + <li>다음으로, <a href="https://github.com/join">GitHub 계정을 위해 가입하세요</a>. 간단하고 쉽습니다.</li> + <li>가입을 하셨다면, github.com 에 여러분의 유저 이름과 암호로 로그인하세요.</li> + <li>그리고나서, 여러분의 파일들이 들어가게될 새로운 repo 를 생성해야 합니다. GitHub 홈페이지의 오른쪽 상단에 있는 플러스 (+) 를 클릭하고, <em>New Repository </em>를 선택하세요.</li> + <li>이 페이지에서, <em>Repository name</em> 박스 안에, <em>username</em>.github.io 를 입력하세요, <em>username</em> 가 있는 곳이 여러분의 유저 이름입니다. 그러니까 예를 들어, 우리 친구 bobsmith 는 <em>bobsmith.github.io </em>를 입력할 것입니다.<img alt="" src="https://mdn.mozillademos.org/files/9479/github-create-repo.png" style="display: block; height: 849px; margin: 0px auto; width: 1392px;"></li> + <li><em>Create repository</em> 를 클릭하세요. 다음과 같은 페이지로 이동하실 겁니다:<img alt="" src="https://mdn.mozillademos.org/files/9481/github-populate-repo.png" style="display: block; height: 849px; margin: 0px auto; width: 1392px;"></li> +</ol> + +<h3 id="GitHub_에_파일_올리기">GitHub 에 파일 올리기</h3> + +<p>이것은 GitHub 에 있는 우리의 repository 를 놓기 위해 사용해볼 커맨드 라인입니다. 커맨드 라인은 파일을 생성하거나 프로그램을 실행하는 것 같은 일을 하기 위해 유저 인터페이스 안에서 클릭을 하는 것 대신 명령어를 입력하는 창입니다. 이렇게 생긴 것입니다:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/9483/command-line.png" style="display: block; height: 478px; margin: 0px auto; width: 697px;"></p> + +<div class="note"> +<p><strong>노트</strong>: 만약 커맨드라인이 불편하시다면, 같은 일을 하기 위해서 <a href="http://git-scm.com/downloads/guis">Git graphical user interface</a> 를 사용하는것도 고려해 볼 수 있습니다.</p> +</div> + +<p><span id="command-line">모든 운영 체제는 커맨드 라인 도구를 갖습니다:</span></p> + +<ul> + <li><strong>윈도우즈</strong>: <strong>Command Prompt</strong> 는 윈도우 키를 누르고 명령 프롬프트 를 입력하고 나타난 리스트에서 이것을 선택하는 것으로 접근할 수 있습니다. 윈도우즈는 리눅스와 맥 OS 와는 다른 그들만의 명령 규칙이 있으므로, 여러분의 장치에 따라 서로 다르다는것을 기억하세요.</li> + <li><strong>맥 OS</strong>: <em>Applications > Utilities 안에 </em><strong>Terminal</strong> 이 있습니다.</li> + <li><strong>리눅스</strong>: 보통 <em>Ctrl + Alt + T</em> 로 터미널을 꺼낼 수 있습니다. 만약 작동하지 않는다면 app 바 또는 메뉴에서 <strong>Terminal </strong>을 찾아보세요.</li> +</ul> + +<p>처음에는 좀 두려우실 수 있지만, 걱정하지마세요 — 기본적인 것들은 금방 익히실 수 있을 것입니다. 무언가를 하기 위해선 명령어를 입력하고 엔터를 누르는 것으로 컴퓨터에게 알려줘야합니다.</p> + +<ol> + <li>커맨드 라인을 여러분의 <code>test-site</code> 폴더로 향하게 합니다 (또는 여러분의 웹사이트가 포함된 어디든지). 그러기 위해선, <code>cd</code> 명령을 사용합니다 (말하자면 "<em>c</em>hange <em>d</em>irectory"). 여기 만약 <code>test-site</code> 폴더 안에 여러분의 웹사이트를 놓으셨다면 여러분이 입력해야 하는 것이 있습니다: + + <pre class="brush: bash">cd Desktop/test-site</pre> + </li> + <li>커맨드 라인이 여러분의 웹사이트 폴더 안을 가리킬 때, 그 폴더를 git repository 가 되도록 <code>git</code> 도구에게 알려주는 다음의 명령을 입력하세요: + <pre class="brush: bash">git init</pre> + </li> + <li>다음으로, GitHub 사이트로 돌아가세요. 현재 페이지에서, you are interested in the section <em>…or push an existing repository from the command line</em>. 이 구역에 나열된 두 코드를 보게 되실 겁니다. 첫 번째 줄의 코드 전체를 복사하고, 커맨드 라인에 붙여넣은 다음, 엔터를 누르세요. 그 명령은 이렇게 보일 것입니다: + <pre class="brush: bash">git remote add origin https://github.com/bobsmith/bobsmith.github.io.git</pre> + </li> + <li>다음으로, 다음 두 명령어를 입력하고, 각 명령마다 엔터를 누릅니다. 이것은 GitHub 에 코드를 올릴 준비를 하는 것이고, Git 에게 그 파일들을 관리하도록 요청합니다. + <pre class="brush: bash">git add --all +git commit -m "adding my files to my repository"</pre> + </li> + <li>마지막으로, GitHub 웹 페이지로 가서 3단계에서 봤던 두 개의 명령어중 두 번째 줄을 터미널에 입력하는 것으로 코드를 푸시합니다: + <pre class="brush: bash">git push -u origin master</pre> + </li> + <li>이제 새 브라우저 탭 (<em>username.github.io</em>) 에서 여러분의 GitHub 페이지의 웹 주소로 갈 때, 여러분의 사이트를 온라인에서 보실 수 있습니다! 친구들에게 메일을 보내서 여러분의 실력을 뽐내보세요.</li> +</ol> + +<div class="note"> +<p><strong>노트</strong>: 만약 막히셨다면, <a href="https://pages.github.com/">GitHub Pages 홈페이지</a> 또한 아주 도움이 될 것입니다.</p> +</div> + +<h3 id="더_많은_GitHub_이해">더 많은 GitHub 이해</h3> + +<p>만약 여러분이 테스트 사이트에 더 많은 변화를 주고 GitHub에 그것들을 업로드하길 원하신다면, 이전에 하신것 처럼 간단하게 파일에 변화를 주면 됩니다. 그리고나서, GitHub에 변화를 푸시하기 위해 다음 명령어를 입력 (각 명령 다음에 엔터누르기) 해야 합니다:</p> + +<pre>git add --all +git commit -m 'another commit' +git push</pre> + +<p><em>another commit</em> 대신에 여러분이 막 변경했던 것을 설명할 수 있는 더 적합한 메시지로 바꾸세요.</p> + +<p>우리는 Git 의 겉을 살짝 건드려 보았습니다. 더 많이 배우시려면, <a href="https://help.github.com/index.html">GitHub Help 사</a>이트 에서 시작하세요.</p> + +<h2 id="마무리">마무리</h2> + +<p>이 지점에서, 특정 웹 주소에서 여러분의 예시 웹사이트를 사용하실 수 있을 것입니다. 수고하셨습니다!</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/9485/hosted-final-site.png" style="display: block; height: 1049px; margin: 0px auto; width: 878px;"></p> + +<p> </p> + +<h2 id="더_읽을거리">더 읽을거리</h2> + +<ul> + <li><a href="/en-US/Learn/What_is_a_web_server">웹 서버는 무엇일까요</a></li> + <li><a href="/en-US/Learn/Understanding_domain_names">도메인 이름 이해하기</a></li> + <li><a href="/en-US/Learn/How_much_does_it_cost">웹에서 무언가를 하기 위한 비용은 얼마나 들까요</a></li> + <li><a href="https://www.codecademy.com/learn/deploy-a-website">Deploy a Website</a>: A nice tutorial from Codecademy that goes a bit further and shows some additional techniques.</li> + <li>Scott Murray 의 <a href="http://alignedleft.com/resources/cheap-web-hosting">Cheap or free static web hosting</a> 에는 이용가능한 서비스를 위한 유용한 정보가 있습니다. </li> +</ul> + +<p>{{PreviousMenuNext("Learn/Getting_started_with_the_web/JavaScript_basics", "Learn/Getting_started_with_the_web/How_the_Web_works", "Learn/Getting_started_with_the_web")}}</p> + +<p> </p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li id="Installing_basic_software"><a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Installing_basic_software">Installing basic software</a></li> + <li id="What_will_your_website_look_like"><a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/What_will_your_website_look_like">What will your website look like?</a></li> + <li id="Dealing_with_files"><a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Dealing_with_files">Dealing with files</a></li> + <li id="HTML_basics"><a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/HTML_basics">HTML basics</a></li> + <li id="CSS_basics"><a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/CSS_basics">CSS basics</a></li> + <li id="JavaScript_basics"><a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/JavaScript_basics">JavaScript basics</a></li> + <li id="Publishing_your_website"><a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Publishing_your_website">Publishing your website</a></li> + <li id="How_the_web_works"><a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/How_the_Web_works">How the web works</a></li> +</ul> + +<p> </p> + +<p> </p> diff --git a/files/ko/learn/getting_started_with_the_web/웹의_동작_방식/index.html b/files/ko/learn/getting_started_with_the_web/웹의_동작_방식/index.html new file mode 100644 index 0000000000..009b22ec8f --- /dev/null +++ b/files/ko/learn/getting_started_with_the_web/웹의_동작_방식/index.html @@ -0,0 +1,99 @@ +--- +title: 웹의 동작 방식 +slug: Learn/Getting_started_with_the_web/웹의_동작_방식 +translation_of: Learn/Getting_started_with_the_web/How_the_Web_works +--- +<p>{{LearnSidebar}}</p> + +<p>{{PreviousMenu("Learn/Getting_started_with_the_web/Publishing_your_website", "Learn/Getting_started_with_the_web")}}</p> + +<div class="summary"> +<p><em>'웹의 동작 방식'</em>은 여러분의 컴퓨터나 폰의 웹 브라우저 안에서 웹페이지를 볼 때 무슨 일이 발생하는지에 대한 간소화된 개념을 제공할 것입니다.</p> +</div> + +<p>이 이론은 단기적으로 봤을 때 웹 코드를 작성하기 위해 필수적인 것은 아니지만, 머지 않아 백그라운드에서 발생하는 것을 이해하는 것으로부터 오는 장점을 얻게 될 것입니다.</p> + +<h2 id="클라이언트와_서버">클라이언트와 서버</h2> + +<p>웹에 연결된 컴퓨터는 <strong>클라이언트 </strong>와 <strong>서버 </strong>라고 합니다. 그들이 어떻게 상호작용하는가에 대한 간소화된 다이어그램은 다음과 같습니다:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/8973/Client-server.jpg" style="height: 123px; width: 336px;"></p> + +<ul> + <li>클라이언트는 일반적인 웹 사용자의 인터넷이 연결된 장치들 (예를 들어, 여러분의 컴퓨터는 WI-FI에 연결되어 있고, 또는 여러분의 폰은 모바일 네트워크에 연결되어 있습니다) 과 이런 장치들에서 이용가능한 웹에 접근하는 소프트웨어 (일반적으로 파이어폭스 또는 크롬 과 같은 웹 브라우저) 입니다.</li> + <li>서버는 웹페이지, 사이트, 또는 앱을 저장하는 컴퓨터입니다. 클라이언트의 장비가 웹페이지에 접근하길 원할 때, 서버로부터 클라이언트의 장치로 사용자의 웹 브라우저에서 보여지기 위한 웹페이지의 사본이 다운로드 됩니다.</li> +</ul> + +<h2 id="도구_상자의_다른_부분들">도구 상자의 다른 부분들</h2> + +<p>위에서 설명한 클라이언트와 서버는 모든 내용을 알려주진 않습니다. 많은 다른 부분들이 포함되어 있고, 아래에서 그것들에 대해 설명할 것입니다.</p> + +<p>지금은, 웹이 도로라고 상상해봅시다. 도로의 한 쪽 끝은 여러분의 집 같은 클라이언트 입니다. 다른 한 쪽 끝은 여러분이 뭔가를 사길 원하는 상점같은 서버입니다.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/9749/road.jpg" style="display: block; height: 427px; margin: 0px auto; width: 640px;"></p> + +<p>클라이언트와 서버에 덧붙여서 우리는 다음 내용들도 알아볼 필요가 있습니다.</p> + +<ul> + <li><strong>인터넷 연결</strong>: 여러분이 웹에서 데이터를 보내고 받을 수 있게 해줍니다. 기본적으로 여러분의 집과 상점 사이의 거리와 같습니다.</li> + <li><strong>TCP/IP</strong>: Transmission Control Protocol (전송 제어 규약) 과 Internet Protocol (인터넷 규약) 은 데이터가 어떻게 웹을 건너 여행해야 하는지 정의하는 통신 규약입니다. 이것은 주문을 하고, 상점에 가고, 또 여러분의 상품을 살 수 있게 해주는 운송 장치와 같습니다. 우리 예시에서, 이것은 차 또는 자전거 (또는 여러분의 두 다리) 와 같습니다.</li> + <li><strong>DNS</strong>: Domain Name System Servers (도메인 이름 시스템 서버) 는 웹사이트를 위한 주소록과 같습니다. 여러분이 브라우저에 웹 주소를 입력할 때, 브라우저는 그 웹사이트를 검색하기 전에 DNS 를 살펴봅니다. 브라우저는 HTTP 메시지를 올바른 장소로 전송하기 위해 그 웹사이트가 있는 서버가 어떤것인지 찾아야 합니다 (아래를 보세요). 이것은 여러분이 접근하기 위해 상점의 주소를 찾아보는 것과 같습니다.</li> + <li><strong>HTTP</strong>: Hypertext Transfer Protocol (하이퍼텍스트 전송 규약) 은 클라이언트와 서버가 서로 통신할 수 있게 하기 위한 언어를 정의하는 어플리케이션 규약 입니다. 이것은 여러분의 상품을 주문하기 위해 여러분이 사용하는 언어와 같습니다.</li> + <li><strong>컴포넌트 파일</strong>: 한 웹사이트는 여러분이 상점에서 사는 다양한 종류의 상품들과 같이 많은 다른 파일들로 만들어집니다. 이 파일들은 두개의 주요한 타입이 있습니다: + <ul> + <li><strong>코드 파일</strong>: 다른 기술들도 잠시 뒤 보게 되실것이지만, 웹사이트는 근본적으로 HTML, CSS, 그리고 JavaScript 로 생성됩니다.</li> + <li><strong>자원</strong>: 이것은 이미지, 음악, 비디오, 단어 문서, 그리고 PDF 같은, 웹사이트를 만드는 모든 다른 것들을 위한 공동적인 이름입니다.</li> + </ul> + </li> +</ul> + +<h2 id="그래서_정확히_무슨일이_발생할까요">그래서 정확히 무슨일이 발생할까요?</h2> + +<p>여러분이 브라우저에 웹 주소를 입력할 때 (우리의 비유에서 상점으로 걸어가는 것과 유사합니다):</p> + +<ol> + <li>브라우저는 DNS 서버로 가서 웹사이트가 있는 서버의 진짜 주소를 찾습니다 (여러분이 상점의 주소를 찾습니다).</li> + <li>그 다음 브라우저는 서버에게 웹사이트의 사본을 클라이언트에게 보내달라는 HTTP 요청 메세지를 서버로 전송합니다.(상점으로 가서 상품을 주문합니다.) 이 메세지, 그리고 클라이언트와 서버 사이에 전송된 모든 데이터는 TCP/IP 연결을 통해서 전송됩니다.</li> + <li>이 메세지를 받은 서버는 클라이언트의 요청을 승인하고, "200 OK" 메세지를 클라이언트에게 전송합니다. "200 OK"는 "물론이죠. 당신은 웹 사이트를 볼 수 있어요! 여기 있어요" 라는 의미입니다. 그 다음 서버는 웹사이트의 파일들을 데이터 패킷이라 불리는 작은 일련의 덩어리들로 브라우저에 전송하기 시작합니다.(상점은 여러분이 주문한 상품을 전달하고, 여러분은 그것을 집으로 가져갑니다.)</li> + <li>브라우저는 이 작은 덩어리들을 완전한 웹 사이트로 조립하고, 당신에게 보여줍니다. (상품이 당신의 문에 도착합니다. — 새 것이죠, 멋져요!)</li> +</ol> + +<h2 id="DNS_설명">DNS 설명</h2> + +<p>실제 웹 주소는 멋지거나, 여러분이 선호하는 웹사이트를 찾기 위한 주소 막대에 입력하는 기억할만한 문자가 아닙니다. 그것은 <code>63.245.217.105</code> 같은 숫자 덩어리입니다.</p> + +<p>이것은 IP 주소라고 하고, 웹의 하나뿐인 특정 위치를 나타냅니다. 그러나 기억하기에 쉽지는 않죠? 그것이 도메인 이름 서버가 발명된 이유입니다. 도메인 이름 서버는 여러분이 브라우저에 입력하는 웹주소 ("mozilla.org" 같은) 를 웹사이트의 실제 (IP) 주소에 맞춰주는 특별한 서버입니다. </p> + +<p>웹사이트는 그들의 IP 주소를 통해 직접 접근될 수도 있습니다. 여러분은 <a href="https://ipinfo.info/html/ip_checker.php">IP Checker</a>와 같은 도구에 도메인을 입력해 IP 주소를 찾을 수 있습니다.</p> + +<h2 id="패킷_설명">패킷 설명</h2> + +<p>앞서 우리는 서버에서 클라이언트로 전송되는 데이터의 포맷을 설명하기 위해 "패킷" 이라는 용어를 사용했습니다. 이게 무엇을 의미하는 걸까요? 기본적으로, 데이터가 웹을 거쳐서 전송될 때, 수천개의 작은 덩어리들로 전송됩니다. 그래서 다양한 웹 사용자들은 동시에 같은 웹 사이트를 다운로드 할 수 있게 됩니다. 만약 웹 사이트가 하나의 큰 덩어리들로 전송된다면, 오직 한 번에 하나의 사용자만 다운로드 할 수 있을 것입니다. 이는 분명 웹을 매우 비효율적이고, 사용하기에 재미없게 만들 것입니다.</p> + +<h2 id="여기도_보세요">여기도 보세요</h2> + +<ul> + <li><a href="/ko/docs/Learn/Common_questions/How_does_the_Internet_work">인터넷 작동 방식</a></li> + <li><a href="https://dev.opera.com/articles/http-basic-introduction/">HTTP — 어플리케이션-계층 규약</a></li> + <li><a href="https://dev.opera.com/articles/http-lets-get-it-on/">HTTP: Let’s GET It On!</a></li> + <li><a href="https://dev.opera.com/articles/http-response-codes/">HTTP: 응답 코드</a></li> +</ul> + +<h2 id="크레딧">크레딧</h2> + +<p>거리 사진: <a href="https://www.flickr.com/photos/kdigga/9110990882/in/photolist-cXrKFs-c1j6hQ-mKrPUT-oRTUK4-7jSQQq-eT7daG-cZEZrh-5xT9L6-bUnkip-9jAbvr-5hVkHn-pMfobT-dm8JuZ-gjwYYM-pREaSM-822JRW-5hhMf9-9RVQNn-bnDMSZ-pL2z3y-k7FRM4-pzd8Y7-822upY-8bFN4Y-kedD87-pzaATg-nrF8ft-5anP2x-mpVky9-ceKc9W-dG75mD-pY62sp-gZmXVZ-7vVJL9-h7r9AQ-gagPYh-jvo5aM-J32rC-ibP2zY-a4JBcH-ndxM5Y-iFHsde-dtJ15p-8nYRgp-93uCB1-o6N5Bh-nBPUny-dNJ66P-9XWmVP-efXhxJ">Street composing</a>, by <a href="https://www.flickr.com/photos/kdigga/">Kevin D</a>.</p> + +<p>{{PreviousMenu("Learn/Getting_started_with_the_web/Publishing_your_website", "Learn/Getting_started_with_the_web")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li id="Installing_basic_software"><a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Installing_basic_software">Installing basic software</a></li> + <li id="What_will_your_website_look_like"><a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/What_will_your_website_look_like">What will your website look like?</a></li> + <li id="Dealing_with_files"><a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Dealing_with_files">Dealing with files</a></li> + <li id="HTML_basics"><a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/HTML_basics">HTML basics</a></li> + <li id="CSS_basics"><a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/CSS_basics">CSS basics</a></li> + <li id="JavaScript_basics"><a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/JavaScript_basics">JavaScript basics</a></li> + <li id="Publishing_your_website"><a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Publishing_your_website">Publishing your website</a></li> + <li id="How_the_web_works"><a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/How_the_Web_works">How the web works</a></li> +</ul> diff --git a/files/ko/learn/getting_started_with_the_web/파일들_다루기/index.html b/files/ko/learn/getting_started_with_the_web/파일들_다루기/index.html new file mode 100644 index 0000000000..1ed38e8cde --- /dev/null +++ b/files/ko/learn/getting_started_with_the_web/파일들_다루기/index.html @@ -0,0 +1,117 @@ +--- +title: 파일 다루기 +slug: Learn/Getting_started_with_the_web/파일들_다루기 +tags: + - Beginner + - CodingScripting + - Files + - Guide + - HTML + - 'l10n:priority' +translation_of: Learn/Getting_started_with_the_web/Dealing_with_files +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Getting_started_with_the_web/What_will_your_website_look_like", "Learn/Getting_started_with_the_web/HTML_basics", "Learn/Getting_started_with_the_web")}}</div> + +<div class="summary"> +<p>웹사이트는 문자, 코드, 스타일시트, 미디어 등 수많은 파일로 구성되어 있습니다. 웹사이트를 제작할 때, 여러분은 이러한 파일들을 여러분의 컴퓨터에 적당한 양식에 맞춰 정리해야 하고, 서로가 잘 작동하는지 확인해야 하며, 최종적으로 <a href="/en-US/Learn/Getting_started_with_the_web/Publishing_your_website">서버에 업로드하기</a> 전에 모든 내용이 올바르게 나타나게 해야 합니다. 파일 다루기에서는 여러분의 웹사이트를 위한 적당한 양식을 만들기 위해 여러분이 알아야 하는 몇 가지 문제들에 대해 이야기 할 것입니다.</p> +</div> + +<h2 id="웹사이트는_컴퓨터의_어디에_두어야_할까요">웹사이트는 컴퓨터의 어디에 두어야 할까요?</h2> + +<p>만약 여러분이 로컬컴퓨터에서 웹사이트에 대해 작업한다면, 퍼블리시된 웹사이트의 파일 구조를 반영하는 하나의 폴더 안에 관련된 모든 파일을 유지하여야 합니다. 이 폴더는 여러분이 원하는 곳이라면 어디에나 둘 수 있지만, 아마도 쉽게 찾을 수 있는 곳에 두어야 할 것입니다. 예를들면 여러분의 바탕화면이나 홈 폴더, 또는 하드 드라이브의 루트(root)가 될 것입니다.</p> + +<ol> + <li>여러분의 웹사이트 프로젝트를 저장할 장소를 선택하세요. 여기에, <code>web-projects</code> (또는 비슷한 이름의 폴더) 라고 불리는 새 폴더를 <u>생성하세요</u>. 이 곳이 여러분의 웹사이트 프로젝트가 위치할 곳입니다.</li> + <li>이 첫 번째 폴더에, 또다른 폴더를 하나 만들고 첫 번째 웹사이트를 저장하도록 합시다. 그 폴더를 <code>test-site</code> (또는 무언가 더 상상력을 발휘한 다른 이름도 좋습니다) 라고 부릅시다.</li> +</ol> + +<h2 id="포장과_공백에_대한_여담">포장과 공백에 대한 여담</h2> + +<p>이 글을 통해 알게 되겠지만, 폴더와 파일의 이름을 지을 때 공백 없이 영문 소문자로 짓기를 바랍니다. 이것은 다음과 같은 이유 때문입니다.</p> + +<ol> + <li>많은 컴퓨터들 -특히 웹 서버- 은 영문 대소문자를 구분합니다. 그래서 예를 들면, 웹사이트에 <code>test-site/<em><strong>M</strong></em>y<strong><em>I</em></strong>mage.jpg라는 </code>이미지를 저장해 두었는데 여러분이 다른 파일에서 <code>test-site/<em><strong>m</strong></em>y<strong><em>i</em></strong>mage.jpg라는 </code>이미지를 호출하는 것은 작동하지 않을 것입니다.</li> + <li>브라우저들과 웹 서버들, 그리고 프로그래밍 언어들은 공백을 일관되게 처리하지 않습니다. 예를 들면, 만약 여러분이 파일 이름에 공백을 사용한다면, 어떤 시스템은 그 파일 이름을 두개의 파일 이름으로 다룰 것입니다. 어떤 서버들은 그 파일 이름의 공백을 "%20"(URIs 안의 공백을 위한 문자 코드)으로 대체하므로 여러분의 모든 링크들을 망가뜨릴 것입니다. 또한, 밑줄문자를 사용하기 보다는 대시(하이픈)으로 단어를 구분하는 것이 훨씬 더 좋습니다.: <code>my-file.html</code> vs.<code> my_file.html</code>.</li> +</ol> + +<p>간단히 말하자면 여러분은 파일 이름을 지을 때 붙임표(hyphen)를 사용해야 합니다. 구글 검색 엔진은 하이픈를 단어 구분자로 취급합니다. 그러나 밑줄문자는 단어 구분자로 취급하지 않습니다. 이러한 이유로, 여러분이 폴더와 파일 이름을 지을 때에는 공백이 없는 영문 소문자와 대시로 구분된 단어로 작성하는 습관을 들이는 것이 제일 좋습니다. 적어도 여러분이 무엇을 하는지 알 때까지는요. 그렇게하면 나중에 발생할 문제를 줄일 수 있습니다.</p> + +<h2 id="웹사이트는_어떤_구조를_가져야_할까요">웹사이트는 어떤 구조를 가져야 할까요?</h2> + +<p>다음으로, 우리의 테스트 사이트가 어떤 구조를 가져야 하는지 살펴 봅시다. 어떤 웹사이트 프로젝트를 만들든지간에 가장 공통으로 가지게 되는 것들은 index HTML 파일과 이미지, 스타일 파일(CSS 파일), 스크립트 파일들을 포함하고 있는 폴더입니다. 이것들을 이제 생성해 봅시다.</p> + +<ol> + <li><code><strong>index.html</strong></code>: 이 파일은 보통은 홈페이지의 내용을 가지고 있습니다. 다시 말하면, 처음 웹사이트에 방문하면 사람들이 볼 수 있는 텍스트나 이미지이 파일 같은 것입니다. 텍스트 에디터를 사용하여, <code>index.html</code> 라는 새 파일을 생성하고 <code>test-site</code> 폴더 안에 저장하세요.</li> + <li><strong><code>images</code> 폴더</strong>: 이 폴더는 여러분의 사이트에 사용할 모든 이미지들을 포함하고 있습니다. <code>test-site</code> 폴더 안에, <code>images</code> 라는 폴더를 생성하세요.</li> + <li><strong><code>styles</code> 폴더</strong>: 이 폴더는 여러분의 내용을 보기 좋게 꾸며주기(예를 들어, 문자와 배경색을 세팅하는 것) 위한 CSS 코드를 포함할 것입니다. <code>test-site</code> 폴더 안에, <code>styles</code> 라는 폴더를 생성하세요.</li> + <li><strong><code>scripts</code> 폴더</strong>: 이 폴더는 모든 JavaScript 코드를 포함하고 있는데, 이 코드는 여러분의 사이트에 상호작용하는 기능을 추가할 때 사용될 것입니다.예를들면, 클릭할 때 자료를 불러오는 버튼). <code>test-site</code> 폴더 안에, <code>scripts</code> 라는 폴더를 생성하세요.</li> +</ol> + +<div class="note"> +<p><strong>참고</strong>: Windows 컴퓨터에서는 파일 이름을 보는것에 문제가 생길 수 있습니다, 왜냐하면 윈도우는 기본적으로 <strong>알려진 확장자 자동 숨김</strong>이라는 귀찮은 옵션을 갖고 있기 때문입니다. 일반적으로 윈도우 익스플로러에서, <strong>폴더 옵션...</strong>에서 알려진 확장자 자동 숨김을 선택 해제하는 것으로 이 옵션을 끌 수 있습니다. 여러분의 윈도우 버전을 포함한 더 많은 정보는, 인터넷에서 검색을 해보세요!</p> +</div> + +<h2 id="파일_경로">파일 경로</h2> + +<p>파일들이 서로 의사소통할 수 있도록 하려면 여러분은 서로에게 각자의 파일 경로를 제공해야 합니다 — 기본적으로 다른 파일이 어디있는지 알 수 있도록 경로를 제공해야하는 것이죠. 이것을 시연해보기 위해, 우리는 <code>index.html</code>파일에 약간의<code>HTML</code>을 작성할 것입니다, 그리고 <a href="/en-US/Learn/Getting_started_with_the_web/What_should_your_web_site_be_like">"웹사이트의 외관은 어떻게 할까요?"</a> 라는 글에서 여러분이 선택한 이미지를 보여주게 할 것입니다.</p> + +<ol> + <li><code>images</code>폴더 안에 여러분이 선택한 이미지를 복사해 넣으세요.</li> + <li><code>index.html</code> 파일을 열고, 아래의 코드를 보이는 그대로 집어 넣습니다. 지금은 이 모든게 무슨 뜻인지 걱정할 필요가 없습니다 — 본 시리즈에서 나중에 이 구조에 대해 더 자세히 살펴볼 겁니다. + <pre class="brush: html notranslate"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>My test page</title> + </head> + <body> + <img src="" alt="My test image"> + </body> +</html> </pre> + </li> + <li><code><img src="" alt="My test image"></code>라는 줄은 페이지 안으로 이미지를 삽입하는 HTML 코드 입니다. 우리는 이미지가 어디에 있는지에 대해 HTML에게 말해줄 필요가 있습니다. 이미지는 <em>images라는</em> 폴더 안에 있는데, 이것은 <code>index.html</code> 파일과 같은 폴더에 있습니다. <code>index.html</code>파일에서 우리 이미지 파일로 파일 구조를 이동하기 위해, 우리가 필요한 파일 경로는 <code>images/your-image-filename</code>입니다. 예를 들어, 우리 이미지가 <code>firefox-icon.png</code>라면, 파일 경로는 <code>images/firefox-icon.png</code>가 됩니다.</li> + <li>여러분의 HTML 코드 중 src="" 의 쌍따옴표 사이에 파일 경로를 입력하세요.</li> + <li>HTML 파일을 저장하고나서, 여러분의 웹 브라우저에서 이것을 로드하세요 (파일을 더블 클릭). 여러분의 새 웹페이지가 이미지를 표시하는 것을 보실 수 있습니다!</li> +</ol> + +<p><img alt="A screenshot of our basic website showing just the firefox logo - a flaming fox wrapping the world" src="https://mdn.mozillademos.org/files/9229/website-screenshot.png" style="display: block; height: 542px; margin: 0px auto; width: 690px;"></p> + +<p>파일 경로를 위한 일반적인 규칙들:</p> + +<ul> + <li>호출하는 HTML 파일과 같은 디렉토리에 있는 파일을 연결하려면 파일이름만 사용하면 됩니다. 예시: <code>my-image.jpg</code>.</li> + <li>하위 폴더에 위치한 파일을 참조하기 위해서는, 디렉토리 이름과 전방향 슬래시(/)를 경로 앞에 추가합니다. 예시: <code>subdirectory/my-image.jpg</code>.</li> + <li>호출하는 HTML 파일의 상위 디렉토리에 있는 파일을 연결하려면, 두 점을 찍어야 합니다. 예를 들면, 만약 <code>index.html</code>가 <code>test-site</code>의 하위 폴더 안에 있고 <code>my-image.png</code>가 <code>test-site</code> 안에 있을 때, 여러분은 <code>../my-image.png</code> 경로를 통해 <code>index.html</code>에서 <code>my-image.png</code>를 참조할 수 있습니다.</li> + <li>여러분이 원하는대로 조합해서 사용할 수도 있습니다, 예를 들면, <code>../subdirectory/another-subdirectory/my-image.png</code>.</li> +</ul> + +<p>지금으로선, 이것이 여러분이 알아야 할 전부 입니다.</p> + +<div class="note"> +<p><strong>노트</strong>: 윈도우 파일 시스템은 기본 슬래시가 아니라 역슬래시를 사용하는 경향이 있습니다. 예시: <code>C:\windows</code>. 이것은 HTML에서 문제가 되지않습니다 — 여러분이 윈도우에서 웹 사이트를 개발하더라도 전방향 슬래시(/)를 코드에 사용해야 합니다.</p> +</div> + +<h2 id="또_무엇을_더_해야할까요">또 무엇을 더 해야할까요?</h2> + +<p>현재로서는 이것이 전부입니다. 여러분의 폴더 구조는 이와 같이 보여야 합니다:</p> + +<p><img alt="A file structure in mac os x finder, showing an images folder with an image in, empty scripts and styles folders, and an index.html file" src="https://mdn.mozillademos.org/files/9231/file-structure.png" style="display: block; height: 577px; margin: 0px auto; width: 929px;"></p> + +<p>{{PreviousMenuNext("Learn/Getting_started_with_the_web/What_will_your_website_look_like", "Learn/Getting_started_with_the_web/HTML_basics", "Learn/Getting_started_with_the_web")}}</p> + + + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li id="Installing_basic_software"><a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Installing_basic_software">Installing basic software</a></li> + <li id="What_will_your_website_look_like"><a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/What_will_your_website_look_like">What will your website look like?</a></li> + <li id="Dealing_with_files"><a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Dealing_with_files">Dealing with files</a></li> + <li id="HTML_basics"><a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/HTML_basics">HTML basics</a></li> + <li id="CSS_basics"><a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/CSS_basics">CSS basics</a></li> + <li id="JavaScript_basics"><a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/JavaScript_basics">JavaScript basics</a></li> + <li id="Publishing_your_website"><a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Publishing_your_website">Publishing your website</a></li> + <li id="How_the_web_works"><a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/How_the_Web_works">How the web works</a></li> +</ul> diff --git a/files/ko/learn/how_to_contribute/index.html b/files/ko/learn/how_to_contribute/index.html new file mode 100644 index 0000000000..08ee091c24 --- /dev/null +++ b/files/ko/learn/how_to_contribute/index.html @@ -0,0 +1,105 @@ +--- +title: MDN의 학습 영역에 기여하는 방법 +slug: Learn/How_to_contribute +tags: + - Documentation + - MDN Meta + - 'l10n:priority' + - 가이드 + - 배우기 + - 참여 + - 초보자 +translation_of: Learn/How_to_contribute +--- +<div>{{LearnSidebar}}</div> + +<p><span id="result_box" lang="ko"><span>처음으로 또는 심도 깊은 검색을 통해 오셨다면 MDN 학습 영역에 참여하는 데 관심이있는 것 같습니다.</span> 그건<span class="alt-edited"> 좋은 소식입니다!</span></span></p> + +<p><span id="result_box" lang="ko"><span>이 페이지에서는 MDN의 학습 콘텐츠를 개선하는 데 필요한 모든 것을 찾을 수 있습니다.</span> <span>얼마나 많은 시간을 가지고 있는지, 초보자이든</span></span><span lang="ko"><span>, 웹 개발자이든</span></span><span lang="ko"><span>, 교사이든</span></span><span lang="ko"><span>, 할 수있는 일이 많이 있습니다.</span></span></p> + +<div class="note"> +<p><strong>Note</strong>: <span id="result_box" lang="ko"><span>새로운 학습 영역 기사를 작성하는 방법에 대한 안내서는 사람들이 웹에 대해 알 수 있도록 기사를 작성하는 방법(</span></span><a href="https://developer.mozilla.org/en-US/docs/MDN/Contribute/Howto/Write_an_article_to_help_learn_about_the_Web"><u><font color="#0066cc">How to write an article to help people learn about the Web</font></u></a><span lang="ko"><span>)을 제공합니다.</span></span></p> +</div> + +<h2 id="특정_작업_찾기"><span class="short_text" id="result_box" lang="ko"><span class="alt-edited">특정 작업 찾기</span></span></h2> + +<p><span id="result_box" lang="ko"><span>참여자는 트</span></span>렐<span lang="ko"><span>로 보드(</span></span><a href="https://trello.com/b/LDggrYSV"><u><font color="#0066cc"><strong>Trello board</strong></font></u></a><span lang="ko"><span>)</span></span>를 사용하여 작업을 구성합니다. 이렇게 하면 프로젝트에서 수행할 특정 작업을 찾을 수 있습니다. 참여하려면 트렐로 계정을 만들고 <u><a href="https://developer.mozilla.org/en-US/profiles/chrisdavidmills">Chris Mills</a></u>에게 보드에 대한 쓰기 액세스 권한을 요청하면 됩니다.</p> + +<p>기여는 새로운 것을 즐겁게 배우는 좋은 방법입니다<span lang="ko"><span>. </span></span>만약 당신이 길을 잃거나 질문이 있으면<span lang="ko"><span> </span></span><a href="https://developer.mozilla.org/ko/docs/MDN/%EC%BB%A4%EB%AE%A4%EB%8B%88%ED%8B%B0"><u><font color="#0066cc">our mailing list</font></u></a> <span lang="ko"><span>또는 </span></span><a href="https://developer.mozilla.org/en-US/docs/MDN/Community#Get_into_IRC"><u><font color="#0066cc">IRC channel</font></u></a><span lang="ko"><span> (자세한 내용은 이 페이지 하단 참조)로 문의하십시오.</span> </span><a href="https://developer.mozilla.org/en-US/profiles/chrisdavidmills"><u><font color="#0066cc">Chris Mills</font></u></a><span lang="ko"><span>는 학습 영역의 핵심 드라이버입니다. 직접 디렉토리에 알림을 보내볼 수도 있습니다.</span></span></p> + +<p>다음 섹션에서는 할 수있는 작업 유형에 대한 일반적인 아이디어를 제공합니다.</p> + +<h2 id="초보자"><span class="short_text" id="result_box" lang="ko"><span>초보자</span></span></h2> + +<div class="trans-verified-button-small" dir="ltr" id="gt-res-dir-ctr">좋습니다! 초보자는 학습 자료에 대한 피드백을 만들고 제공하는 데 매우 중요하고 가치가 있습니다. 이 기사에 대한 독자적인 시각을 잠재 고객의 구성원으로 확보하면 우리 팀의 소중한 구성원이 될 수 있습니다. 실제로, 만약 당신이 무언가를 배우기 위해 우리의 글 중 하나를 사용하여 곤경에 빠지거나 글을 약간 혼란스럽게 하는 것을 발견한다면, 문제를 해결하거나 문제에 대해 알려줌으로써 해결할 수 있습니다.</div> + +<div class="trans-verified-button-small" dir="ltr"></div> + +<p><span class="short_text" id="result_box" lang="ko"><span>다음은 </span></span>참여<span class="short_text" lang="ko"><span> 할 수있는 몇 가지 제안 방법입니다.</span></span></p> + +<dl> + <dt><span class="short_text" id="result_box" lang="ko"><span>기사에 태그 추가[</span></span><a href="/en-US/docs/MDN/Contribute/Howto/Tag">Add tags to our articles</a>] (<em>5 min</em>)</dt> + <dd><span id="result_box" lang="ko"><span>MDN 컨텐츠에 태그를 지정하는 것은 MDN에 기여하는 가장 쉬운 방법 중 하나입니다.</span> </span>많은 기능이 정보를 제공하기 위해 태그를 사용하므로 태그 지정을 돕는 것은 매우 가치가 있는 공헌입니다.<span lang="ko"> <span>시작하려면 태그가없는 용어집 항목(<u><a href="https://developer.mozilla.org/ko/docs/MDN/Doc_status/Glossary">glossary entries</a></u>) 및 학습 기사(<u><a href="https://developer.mozilla.org/ko/docs/MDN/Doc_status/Learn">learning articles</a></u>) 목록을 살펴보십시오.</span></span></dd> + <dt>용어 사전<span class="short_text" lang="ko"><span> 항목 읽기 및 검토</span></span>[<a href="https://developer.mozilla.org/ko/docs/Glossary">Read and review a glossary entry</a>] (<em>5 min</em>)</dt> + <dd><span id="result_box" lang="ko"><span>우리는 당신이 초보자로서 우리의 콘텐츠를 바라 보는 신선한 눈을 필요로 합니다.</span> <span>용어집을 쉽게 이해할 수 없다면 항목을 개선해야한다는 의미입니다.</span> <span>필요하다고 생각되는 부분은 자유롭게 변경하십시오.</span> <span>자신이 직접 항목을 편집 할 수있는 적절한 기술이 없다고 생각한다면 </span></span><u><a href="https://developer.mozilla.org/en-US/docs/MDN/Community#Join_our_mailing_lists">our mailing list</a></u>로 알려주십시오.</dd> + <dt>새로운 용어집 항목 작성[<a href="/docs/MDN/Contribute/Howto/Write_a_new_entry_in_the_Glossary">Write a new glossary entry</a>] (<em>20 minutes</em>)</dt> + <dd> + <div id="gt-res-wrap"> + <div id="gt-res-content"> + <div class="trans-verified-button-small" dir="ltr" id="gt-res-dir-ctr"><span id="result_box" lang="ko"><span>이것은 새로운 것을 배우는 가장 효과적인 방법입니다.</span> <span>이해하려는 개념을 고르고, 그것에 대해 배울 때 그에 관한 용어집 항목을 작성하십시오.</span> <span>다른 사람들에게 무언가를 설명하는 것은 지식을 "시멘트"로 만들고 다른 사람들을 돕는 동안 자신이 이해할 수 있게 하는 훌륭한 방법입니다.</span> 모두에게 이득입니다<span>!</span></span></div> + </div> + </div> + </dd> + <dt><span class="short_text" id="result_box" lang="ko"><span>학습 자료 읽기 및 검토</span></span>[<a href="/en-US/Learn/Index">Read and review a learning article</a>] (<em>2 hours</em>)</dt> + <dd> + <div class="g-unit" id="gt-res-c"> + <div id="gt-res-p"> + <div id="gt-res-data"> + <div id="gt-res-wrap"> + <div id="gt-res-content"> + <div class="trans-verified-button-small" dir="ltr" id="gt-res-dir-ctr"><span id="result_box" lang="ko"><span>이것은 </span></span>용어 사전 <span lang="ko"><span> 항목을 검토하는 것과 같습니다. (위 참조)</span> <span>이 기사는 일반적으로 꽤 길기 때문에 더 많은 시간이 걸립니다.</span></span></div> + </div> + </div> + </div> + </div> + </div> + </dd> +</dl> + +<h2 id="웹_개발자">웹 개발자</h2> + +<p><span id="result_box" lang="ko"><span>좋습니다!</span> 당신의 <span>기술 능력은 초보자에게 기술적으로 정확한 내용을 제공하기 위해 필요한 것입니다.</span> <span>MDN의 이 특정 부분은 웹 학습에만 전념하므로 유용한 설명이 아닌 단순하지 않은 설명을 가능한 간단하게 작성하십시오.</span> <span>지나치게 정확한 것보다 이해하는 것이 더 중요합니다.</span></span></p> + +<dl> + <dt><span class="short_text" id="result_box" lang="ko"><span>용어집 항목 읽기 및 검토</span></span>[<a href="https://developer.mozilla.org/ko/docs/Glossary">Read and review a glossary entry</a>] (<em>5 min</em>)</dt> + <dd>웹 개발자로서, 우리의 콘텐츠가 지나치게 규칙적이지 않으면서 기술적으로 정밀한 지 확인해 주길 바랍니다. 필요하다고 생각되는 부분을 자유롭게 변경하십시오. 콘텐츠를 편집하기 전에 논의하기를 원하시면 <a href="/en-US/docs/MDN/Community#Join_our_mailing_lists">our mailing list</a>나 <a href="/en-US/docs/MDN/Community#Get_into_IRC">IRC channel</a>로 알림을 보내주십시오.</dd> + <dt><span class="short_text" id="result_box" lang="ko"><span>새로운 용어집 항목 작성</span></span>[<a href="/docs/MDN/Contribute/Howto/Write_a_new_entry_in_the_Glossary">Write a new glossary entry</a>] (<em>20 minutes</em>)</dt> + <dd>기술적인 전문 용어를 명확히 하는 것은 기술적으로 정확하고 간결하게 배우는 좋은 방법이다. 초보자들은 그에 감사할 것입니다. 당신의 도움이 필요한 정의되지 않은 용어(<a href="/en-US/docs/Glossary#Contribute">many undefined terms</a>)가 많이 있습니다. 선택해서 작성하실 수 있습니다. </dd> + <dt><span class="short_text" id="result_box" lang="ko"><span>학습 자료 읽기 및 검토</span></span>[<a href="/en-US/Learn/Index">Read and review a learning article</a>] (<em>2 hours</em>)</dt> + <dd>이것은 용어집을 읽고 검토하는 것과 같습니다. (위 참조) 이 기사는 일반적으로 꽤 길기 때문에 더 많은 시간이 걸립니다.</dd> + <dt><span class="short_text" id="result_box" lang="ko"><span>새로운 학습 기사 작성</span></span>[<a href="/en-US/docs/MDN/Contribute/Howto/Write_an_article_to_help_learn_about_the_Web">Write a new learning article</a> ](<em>4 hours or more</em>)</dt> + <dd>MDN는 웹 기술사용에 관한 간단한 기사가 부족합니다. (<a href="/en-US/docs/Learn/CSS">HTML</a>, <a href="/en-US/docs/Learn/CSS">CSS</a>, <a href="/en-US/docs/Learn/JavaScript">JavaScript</a>, 등)MDN은 다소 오래 된 콘텐츠들이 있고, 그를 검토하고 개정할 필요가 있습니다. 기술을 최대한 초보자에게도 웹 기술을 이용하기 쉽게 작성하십시오.</dd> + <dt><span class="short_text" id="result_box" lang="ko"><span>연습, 코드 샘플 또는 대화식 학습 도구 만들기</span></span>[<a href="/en-US/docs/MDN/Contribute/Howto/Create_an_interactive_exercise_to_help_learning_the_web">Create exercises, code samples or interactive learning tools</a>](<em>? hours</em>)</dt> + <dd>우리의 모든 학습 기사는 “능동적 학습" 자료라고 부르는 것을 요구합니다.<span lang="ko"><span> 왜냐하면 사람들은 스스로 뭔가를 함으로써 최선을 다해 배우기 때문입니다.</span> <span>이러한 자료는 사용자가 기사에 설명 된 개념을 적용하고 조작하는 데 도움이 되는 연습이나 대화형 콘텐츠입니다. </span></span><a href="http://jsfiddle.net/" rel="external"><u><font color="#0066cc">JSFiddle</font></u></a> <span lang="ko"><span>또는 그와 유사한 코드 샘플을 만드는 것에서 </span></span><a href="https://thimble.mozilla.org/" rel="external"><u><font color="#0066cc">Thimble</font></u></a><span lang="ko"><span>을 사용하여 </span></span>완전히 공유된 대화형 콘텐츠를 만드는 것까지 능동적인 학습 콘텐츠를 만드는 방법은 다양합니다. 창의력을 발휘하십시오!</dd> +</dl> + +<h2 id="교육자">교육자</h2> + +<p><span id="result_box" lang="ko"><span>MDN은 기술적 우수성에 대한 오랜 역사를 가지고 있지만 새로 온 사람들에게 개념을 가르치는 가장 좋은 방법에 대한 깊이 있는 이해가 부족합니다.</span> <span>이것은 우리가 교사 또는 교육자로서 당신을 필요로 하는 이유입니다.</span> <span>자료를 통해 독자에게 훌륭한 교육 자료를 제공 할 수 있습니다.</span></span></p> + +<dl> + <dt><span class="short_text" id="result_box" lang="ko"><span>용어집 항목 읽기 및 검토</span></span>[<a href="https://developer.mozilla.org/ko/docs/Glossary">Read and review a glossary entry</a>] (<em>15 min</em>)</dt> + <dd><span id="result_box" lang="ko"><span>용어집 항목을 확인하고 필요하다고 생각되는 부분을 자유롭게 변경하십시오.</span> <span>편집하기 전에 내용을 토론하고 싶다면 </span></span><a href="https://developer.mozilla.org/en-US/docs/MDN/Community#Join_our_mailing_lists"><u><font color="#0066cc">our mailing list</font></u></a><span lang="ko"><span> 나 </span></span><a href="https://developer.mozilla.org/en-US/docs/MDN/Community#Get_into_IRC"><u><font color="#0066cc">IRC channel</font></u></a><span lang="ko"><span>로 알림을 보내주십시오.</span></span></dd> + <dt><span class="short_text" id="result_box" lang="ko"><span>새로운 용어집 항목 작성</span></span>[<a href="/docs/MDN/Contribute/Howto/Write_a_new_entry_in_the_Glossary">Write a new glossary entry</a>] (<em>1 hour</em>)</dt> + <dd><span id="result_box" lang="ko"><span>용어의 명확하고 간단한 정의와 용어집의 기본 개념은 초보자의 필요를 충족시키는 데 중요합니다.</span> <span>교육자로서의 경험은 훌륭한 용어집 항목을 만드는 데 도움이 될 수 있습니다.</span> <span>우리는 주의가 필요한 많은 정의되지 않은 용어(</span></span><a href="https://developer.mozilla.org/en-US/docs/Glossary#Contribute"><u><font color="#0066cc">many undefined terms</font></u></a><span lang="ko"><span>)를 가지고 있습니다.</span> </span>하나를 선택하고 작성하실 수 있습니다.</dd> + <dt><span class="short_text" id="result_box" lang="ko"><span>기사에 삽화 또는 도식을 추가</span></span>[<a href="/en-US/docs/tag/needsSchema">Add illustrations and/or schematics to articles]</a> (<em>1 hour</em>)</dt> + <dd><span id="result_box" lang="ko"><span>아시다시피, 삽화는 모든 학습 콘텐츠의 중요한 부분입니다.</span> <span>이것은 종종 MDN에서 부족한 부분이며 당신의 기술이 해당 영역에서 변화를 가져올 수 있습니다.</span> <span>설명이 부족한 기사(</span></span><a href="https://developer.mozilla.org/en-US/docs/tag/needsSchema"><u><font color="#0066cc">articles that lack illustrative content</font></u></a><span lang="ko"><span>)를 확인하고 </span></span>삽화를 삽입하고 싶은 기사를 선택하십시오.</dd> + <dt><span class="short_text" id="result_box" lang="ko"><span>학습 자료 읽기 및 검토</span></span>[<a href="/en-US/Learn/Index">Read and review a learning article</a>] (<em>2 hours</em>)</dt> + <dd><span id="result_box" lang="ko"><span>이것은 용어집 항목을 검토하는 것과 비슷하지만 (위 참조) 일반적으로 기사가 상당히 길기 때문에 더 많은 시간이 필요합니다.</span></span></dd> + <dt><span class="short_text" id="result_box" lang="ko"><span>새로운 학습 기사 작성</span></span>[<a href="/en-US/docs/MDN/Contribute/Howto/Write_an_article_to_help_learn_about_the_Web">Write a new learning article</a>] (<em>4 hours</em>)</dt> + <dd>우리는 웹 생태계와 그 주변의 다른 기능적 주제에 대한 간단하고 직접적인 기사가 필요합니다. 이 학습 기사는 말 그대로 문자 그대로 모두를 다루려고 하기 보다는 교육적일 필요가 있기 때문에 무엇을 알아야하고 어떻게 하면 훌륭한 자산이 될지를 아는 당신의 경험으로 도움을 줄 수 있습니다.</dd> + <dt><span class="short_text" id="result_box" lang="ko"><span>연습 문제, 퀴즈 또는 대화식 학습 도구 만들기</span></span>[<a href="/en-US/docs/MDN/Contribute/Howto/Create_an_interactive_exercise_to_help_learning_the_web">Create exercises, <abbr title="Multiple Choice Tests">quizzes</abbr> or interactive learning tools</a>] (<em>? hours</em>)</dt> + <dd><span id="result_box" lang="ko"><span>우리의 모든 학습 기사에는 "능동적 학습" 자료가 필요합니다.</span> <span>이러한 자료는 사용자가 기사에서 설명하는 개념을 사용하고 확장하는 방법을 배우는 데 도움이 되는 연습 또는 대화형 콘텐츠입니다.</span> </span><a href="https://thimble.mozilla.org/" rel="external"><u><font color="#0066cc">Thimble</font></u></a><span lang="ko"><span>와 함께 </span></span>공유된 양방향 콘텐츠를 만드는 것부터 퀴즈 만들기에 이르기까지 여기에서 할 수 있는 많은 것들이 있습니다. 창의력을 발휘하십시오!</dd> + <dt><span class="short_text" id="result_box" lang="ko"><span>학습 경로 만들기</span></span>[<a href="/en-US/docs/MDN/Contribute/Howto/Create_learning_pathways">Create learning pathways</a> ](<em>? hours</em>)</dt> + <dd>진보적이고 이해하기 쉬운 자습서를 제공하려면 콘텐츠를 하나의 경로로 만들어야 합니다. 기존 콘텐츠를 수집하고 누락된 부분을 찾아서 작성할 학습 기사를 만들 수 있습니다.</dd> +</dl> diff --git a/files/ko/learn/html/forms/html_폼_구성_방법/index.html b/files/ko/learn/html/forms/html_폼_구성_방법/index.html new file mode 100644 index 0000000000..37bfbb57ae --- /dev/null +++ b/files/ko/learn/html/forms/html_폼_구성_방법/index.html @@ -0,0 +1,928 @@ +--- +title: HTML_폼_구성_방법 +slug: Learn/HTML/Forms/HTML_폼_구성_방법 +translation_of: Learn/Forms/How_to_structure_a_web_form +--- +<p>HTML폼을 만들떄 구조화 하는것은 중요한 것이다. 이것은 두가지 이유로 중요하다. 폼이 사용 할수 있다는 것을 보장하고 접근성도 늘릴수 있기 떄문이다.(즉 장애인들도 쉽게 사용할 수 있다.) <span style="line-height: 1.5;">HTML 폼의 <a href="https://developer.mozilla.org/en-US/docs/Web/Accessibility">접근성</a>은 중요한 점이고 어떻게 폼 접근성을 높일 수 있는지 볼것이다.</span></p> + +<p><span style="line-height: 1.5;">HTML 폼들은 그 유연성으로 인해 HTML 중 복잡한 구조를 가지고 있는 요소중 하나이다. </span>폼 요소와 속성을 잘 혼합하면 모든 형태의 기본적인 폼을 만들 수 있다. 즉 몇몇 사람들이 HTML폼이 단순하고 매우 거칠다는 것을 발견했다는 것에 주목할 가치가 있다. <a href="https://developer.mozilla.org/en-US/docs/Archive/Web/XForms">XForms</a>같은 풍부한 기술이 있다는 것은 사실이지만 불행하게도 모든 브라우저에서 폼의 종류를 널리 구현되지 않았다. 왜냐하면 대부분 자바스크립트에 의존하여 HTML폼들을 다루기 떄문이다.이 문서에서는 HTML 폼 요소들을 어떻게 사용해야 하는지 자세하게 설명 할 것이다. 만약 사용자 폼 위젯 만들기에 대하여 자세한 내용을 알고 싶다면 다음 문서를 참조하시오. <a href="/en-US/docs/HTML/Forms/How_to_build_custom_form_widgets" title="/en-US/docs/HTML/Forms/How_to_build_custom_form_widgets">How to build custom form widgets</a></p> + +<h2 id="글로벌_구조" style="line-height: 30px;">글로벌 구조</h2> + +<h3 id="<form>_요소" style="line-height: 24px;"><form> 요소</h3> + +<p>{{HTMLElement("form")}} 요소는 공식적으로 폼을 정의하는 요소로 이 요소의 속성으로 폼의 작동하는 방식을 정의 할 수있다. HTML폼을 생성할떄마다 반드시 이 요소로 시작을 해야한다. 많은 보조 기술이나 브라우저 플러그인이 {{HTMLElement("form")}} 요소를 발견하고 쉽게 사용 할 수 있게 특별한 후크를 구현 할 수 있다.</p> + +<p>우리는 저번 문서에서 이미 이 내용을 다루었다.</p> + +<div class="note"><strong>주의:</strong>폼을 다른 폼으로 둘러싸는 것은 엄격하게 제한되어 있다. 만약 그렇게 하면 사용자가 사용하는 브라우저에 따라 예측할 수 없는 방식으로 작동하게 된다.</div> + +<p>언제든지 폼위젯을 {{HTMLElement("form")}} 요소 바깥에서 사용할 수 있다. 하지만 그렇게 사용한다면, 그 폼위젯은 어떠한 폼과도 관련이 없다. 폼 위젯들은 폼 바깥에서 사용될 수 있지만, 그 위젯들은 스스로 아무것도 하지 않을 것이기 때문에 당신이 그 위젯들 전용 프로세스를 만들어주어야 한다. 당신은 자바스크립트로 그 동작을 정의해주어야 한다.</p> + +<div class="note"> +<p><strong>주의:</strong>HTML5에서 HTML 폼 요소안의 폼 속성이 지원된다. 폼 속성은 {{HTMLElement("form")}} 바깥에 있는 폼요소라도 폼과 명시적으로 연결한다. 불행하게도 지금 시점에 이 기능은 다양한 브라우저에서 안정적으로 구현되지 않아서 신뢰할 수 없다.</p> +</div> + +<p>{{HTMLElement("form")}} 요소는 다음과 같은 속성을 가지고 모든 속성이 필수가 아닌 선택적이다.</p> + +<p><br> + <strong style="font-style: inherit; font-weight: bold; line-height: 1.5;"> {{HTMLElement("form")}} 요소 속성</strong></p> + +<table> + <thead> + <tr> + <th scope="col">속성 이름</th> + <th scope="col">기본값</th> + <th scope="col">설명</th> + </tr> + </thead> + <tbody> + <tr> + <td style="white-space: nowrap;">{{htmlattrxref("accept-charset","form")}}</td> + <td><code>UNKNOWN</code></td> + <td>서버가 받아들일 문자 인코딩의 형식을 지정한다. 기본값은 특수 문자열 <span style="font-family: 'Courier New','Andale Mono',monospace; line-height: normal;">UNKNOWN</span><span style="line-height: 1.5;">이고 이경우에 폼 요소 안에 있는 문서의 인코딩에 맞는 인코딩이다.</span></td> + </tr> + <tr> + <td>{{htmlattrxref("action","form")}}</td> + <td> </td> + <td>폼을 통해서 전송한 정보를 처리하는 웹페이지의 URL </td> + </tr> + <tr> + <td>{{htmlattrxref("autocomplete","form")}}</td> + <td><code>on</code></td> + <td>이 속성은 이 폼안에 있는 위젯들의 기본값이 브라우저에 의해 자동 완성 하게 하는지 여부를 나타낸다. 이속성은 두가지 값중 하나를 같는다. <code>on</code> 또는 <code>off</code>.</td> + </tr> + <tr> + <td>{{htmlattrxref("enctype","form")}}</td> + <td><code>application/x-www-form-urlencoded</code></td> + <td>\<code>method</code> 속성이 <code>post 값으로 지정되면</code>, 서버로 폼을 전송하는 콘텐츠 <a href="http://en.wikipedia.org/wiki/Mime_type">MIME</a>의 타입을 지정한다.: + <ul> + <li><code>application/x-www-form-urlencoded</code></li> + <li><code>multipart/form-data</code>: {{HTMLElement("input")}}요소의 <span style="font-family: 'Courier New','Andale Mono',monospace; line-height: normal;">type</span> 속성을 <em>file</em>로 지정한 경우 이 속성의 값을 사용한다. </li> + <li><code>text/plain</code></li> + </ul> + </td> + </tr> + <tr> + <td>{{htmlattrxref("method","form")}}</td> + <td><code>get</code></td> + <td><span style="line-height: 1.5;">브라우저가 폼을 전송하기위해 사용하는 <a href="http://www.w3.org/Protocols/rfc2616/rfc2616.html">HTTP</a>의 방식을 지정한다.</span><br> + <span style="line-height: 1.5;">이 속성은 두개의 값중 한개를 가진다.</span> <code>get</code> 또는 <code>post</code>.</td> + </tr> + <tr> + <td>{{htmlattrxref("name","form")}}</td> + <td> </td> + <td>폼의 이름이다. 이 속성값은 반드시 문서의 폼 사이에서 고유해야하며 빈 문자열을 지정할 수없다. 일반적으로 <span style="font-family: 'Courier New','Andale Mono',monospace; line-height: normal;">id</span> 속성으로 대신 지정할 수 있다.</td> + </tr> + <tr> + <td>{{htmlattrxref("novalidate","form")}}</td> + <td>(<em>false</em>)</td> + <td>이 불리언 속성은 폼이 전송 할떄 유효성 검사를 할수 없음을 나타낸다.</td> + </tr> + <tr> + <td>{{htmlattrxref("target","form")}}</td> + <td><code>_self</code></td> + <td>폼 요청을 전송한후 응답을 어떻게 받을것인지 지정한다. 예를들어 {{HTMLElement("iframe")}}, tab, window를 사용 할 수 있다. 이 속성의 키워드로 다음과 같은 값을 사용 할 수있다. + <ul> + <li><code>_self</code>: 응답을 현재 브라우징 컨텍스트 ({{HTMLElement("iframe")}}, tab, window 등)에서 불러온다.</li> + <li><code>_blank</code>: 응답을 새로운 브라우징 컨텍스트로 불러온다.</li> + <li><code>_parent</code>: 응답을 현재의 브라우징 컨텍스트의 부모 브라우징 컨텍스트에서 불러온다. 만약 부모가 없다면 <code>_self 키워드와 똑같이 작동한다</code>.</li> + <li><code>_top</code>: 응답을 최상휘 레벨 브라우징 컨텍스트에서 불러온다. 만약 최상위 컨텍스트가 없다면 <code>_self 키워드와 똑같이 작동한다</code>.</li> + </ul> + </td> + </tr> + </tbody> +</table> + +<p>요소 밖에 폼 위젯들을 사용 할 수 있지만, 폼 위젯이 어떠한 폼과도 상관이 없다는 것을 유의 해야 한다.폼의 밖에서 위젯을 사용하는 것은 편리할 수 있지만 위젯들이 작동하기 위해 다른 것들을 해야 한다는 것을 의미한다. 아마 자바스크립트를 이용해서 동작을 정의 해야 할것이다.</p> + +<p><span style="line-height: 1.5;">기술적으로 HTML5는 HTML 폼 요소에서 폼 속성을 설명 했다.</span> 이것은 요소들을 실제로 {{ HTMLElement("form") }} 안에 있지 않아도 form요소로 확실하게 바인딩 하도록 해야한다. 불행하게도 모든 브라우저가 아직 이것을 충분히 지원하지 않는다.</p> + +<h3 id="<fieldset>_와_<legend>_요소" style="line-height: 24px;"> <fieldset> 와 <legend> 요소</h3> + +<p>{{HTMLElement("fieldset")}}요소는 같은 목적을 가진 위젯들을 편리하게 그룹화 하는 방법이다. A {{HTMLElement("fieldset")}} 요소는 라벨인 {{HTMLElement("legend")}} 요소와 같이 사용된다. {{HTMLElement("legend")}} 요소는 공식적으로 {{HTMLElement("fieldset")}} 요소를 설명하는데 사용된다. 많은 보조 기술들이 {{HTMLElement("legend")}} 요소를 {{HTMLElement("fieldset")}} 요소의 라벨로 이용하는데 사용된다. 예를 들어 <span style="line-height: 1.5;"> </span><a href="http://www.freedomscientific.com/products/fs/jaws-product-page.asp" rel="external" style="line-height: 1.5;" title="http://www.freedomscientific.com/products/fs/jaws-product-page.asp">Jaws</a>,<span style="line-height: 1.5;"> </span><a href="http://www.nvda-project.org/" rel="external" style="line-height: 1.5;" title="http://www.nvda-project.org/">NVDA</a><span style="line-height: 1.5;">같은 스크린 리더들은 각각의 위젯의 라벨을 읽기전에 legend들을 읽을 것이다.</span><span style="line-height: 1.5;"> </span></p> + +<p>아래 조그만 예제가 있다.</p> + +<pre class="brush:html;" style="font-size: 14px;"><form> + <fieldset> + <legend>Fruit juice size</legend> + <p> + <input type="radio" name="size" id="size_1" value="small" /> + <label for="size_1">Small</label> + </p> + <p> + <input type="radio" name="size" id="size_2" value="medium" /> + <label for="size_2">Medium</label> + </p> + <p> + <input type="radio" name="size" id="size_3" value="large" /> + <label for="size_3">Large</label> + </p> + </fieldset> +</form></pre> + +<p>이 예제를 스크림 리더가 Fruit juice size small을 먼저 읽고 Fruit juice size medium을 읽은 다음 마지막으로 Fruit juice size large을 읽을 것이다,</p> + +<p>이것은 가장 중요한것 중 하나이다. 대부분 라디오 버튼을 설정할떄 마다{{HTMLElement("fieldset")}} 요소 안에 있는지 확인해야한다. 다르게 사용하는 사례가 있지만 일반적으로 {{HTMLElement("fieldset")}} 요소는 폼을 강력하게 사용할 수 있게 해준다. 보조기술의 영향으로 {{HTMLElement("fieldset")}} 요소는 폼 접근 할수 있는 키 요소 중 하나이다. 이것을 남용하지 않는 것은 개발자 책임이다. 가능한 폼을 만들떄마다 스크린리더로 들어보면서 하는 것이 좋다. 만약 말이 이상하게 들린다면 개선 해야 한다는 신호이다.</p> + +<p>{{HTMLElement("fieldset")}} 요소는 다음과 같은 속성을 지정한다.</p> + +<table> + <caption>{{HTMLElement("fieldset")}} 요소의 속성</caption> + <thead> + <tr> + <th scope="col">속성 이름</th> + <th scope="col">기본값</th> + <th scope="col">설명</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{htmlattrxref("disabled","fieldset")}}</td> + <td>(<em>false</em>)</td> + <td>만약 이 불리언 속성이 설정되면 폼은(첫번째 {{ HTMLElement("legend") }}요소에 있는 요소는 예외이다. ) 이것에 파생된 요소를 사용하거나 편집 할 수없게된다. 그리고 마우스 클릭같은 어떠한 브라우저 이벤트들도 받지 않을것이다. 일반적으로 브라우저는 회색으로 이를 표시할 것이다.</td> + </tr> + </tbody> +</table> + +<h3 id="The_<label>_element" style="line-height: 24px;">The <label> element</h3> + +<p>{{HTMLElement("label")}} 요소는 HTML 폼 위젯을 정의하는 공식적인 방법이다. 이것은 접근성 있는 폼을 만드는데 가장 중요한 요소이다.</p> + +<p>{{HTMLElement("label")}} 요소는 다음과 같은 속성을 지원한다.</p> + +<p><br> + <strong style="font-style: inherit; font-weight: bold; line-height: 1.5;">{{HTMLElement("label")}} </strong><span style="font-style: inherit; line-height: 1.5;">요소의 속성</span></p> + +<p><br> + </p> + +<table> + <thead> + <tr> + <th scope="col">속성 명</th> + <th scope="col">기본값</th> + <th scope="col">설명</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{htmlattrxref("for","label")}}</td> + <td> </td> + <td>{{HTMLElement("label")}} 요소와 같은 문서에 있는 위젯의 라벨의 ID . 문서안의 ID와 for속성 값이 같으면 그 라벨 요소는 그 위젯의 라벨이된다.</td> + </tr> + </tbody> +</table> + +<p><span style="line-height: 1.5;">요소는 for속성으로 지정한 위젯과 묶여진다. </span>for속성은 해당 위젯의 실제 id 속성을 참조한다. <span style="line-height: 1.5;">위젯은 요소로 둘러싸게 할수 있지만 이 경우 몇가지 보조 기술이 라벨과 위젯의 암시적인 관계를 이해하지 못하기 떄문에 for 속성을 고려 해봐야한다.</span></p> + +<p>심지어 보조 기술을 배제 한다고 하여도 모든 브라우저에서 공식적인 라벨 설정하면 사용자가 라벨을 누르면 해당하는 위젯이 활성화 할수 있다는 것을 알아 두어야한다. 이것은 라디오 버튼이나 체크박스를 사용하는데 특히 유용하다.</p> + +<pre class="brush:html;" style="font-size: 14px;"><form> + <p> + <input type="checkbox" id="taste_1" name="taste_cherry" value="1"> + <label for="taste_1">I like cherry</label> + </p> + <p> + <label for="taste_2"> + <input type="checkbox" id="taste_2" name="taste_banana" value="1"> + I like banana + </label> + </p> +</form></pre> + +<p>몇가지 보조 기술은 여러개의 라벨을 한개의 위젯을 다루면 문제를 가질수 있다. 이 떄문에 위젯을 그에 맞는 폼 요소안에 넣어서 사용해야한다.</p> + +<p>다음 예제를 보아라</p> + +<pre class="brush:html;" style="font-size: 14px;"><form> + <p>Required fields are followed by <strong><abbr title="required">*</abbr></strong>.</p> + + <p> + <label for="name"> + <span>Name: </span> + <input type="text" id="name" name="username" required /> + <strong><abbr title="required">*</abbr></strong> + </label> + </p> + + <p> + <label for="birth"> + <span>Date of birth: </span> + <input type="text" id="birth" name="userbirth" maxlength="10" /> <em>formated as mm/dd/yyyy</em> + </label> + </p> +</form></pre> + +<p>이 예제에서 첫번째 단락은 필수적인 요소의 규칙들을 정의한다. 이 것은 스크린 리더와 같은 보조 기술이 필수 요소들을 찾기전에 출력하거나 읽기 위해서는 반드시 시작부분 나타내야 한다. <span style="line-height: 1.5;">이런식으로 사용자는 항상 자신이 무엇을 하는지 알 수있다.</span></p> + +<p>첫번째 필드는 필수적이기 떄문에 라벨 요소는 name 과 * 로 필수적인 필드를 나타낸다 이런 식으로 하면 스크린 리더는 "Name star" 또는 "Name required"이라고 읽을 것이다. ( 스크린 리더의 설정에 따라 다르지만 항상 첫번째 단락에서 읽어진 것을 읽는다). 만약 두가지 라벨을 사용한다면, 사용자가 이 요소가 필수 요소 인지 보여지는지 보장 할 수없다.</p> + +<p>두번째 폼 요소는 비슷하게 작동한다. 이 기술을 사용하면 사용자에게 어떻게 데이터를 작성하는지 알려주는데 확신 할 수 있다.</p> + +<h3 id="<output>_요소" style="line-height: 24px;"><output> 요소</h3> + +<p>이 요소는 계산의 출력을 저장하는데 사용된다. It formally defines a relationship between the fields used to get the data required to perform the calculation and an element to be used to display the results. It is also understood as a live region by some assistive technologies (which means that when the content of the {{HTMLElement("output")}} element changes, the assistive technology is aware of that change and can react to it).</p> + +<p>{{HTMLElement("output")}} 요소는 다음 속성은 지원한다.</p> + +<table> + <caption>{{HTMLElement("output")}} 요소 속성</caption> + <thead> + <tr> + <th scope="col">Attribute name</th> + <th scope="col">Default value</th> + <th scope="col">Description</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{htmlattrxref("for","output")}}</td> + <td> </td> + <td>스페이스로 구분된 다른 요소의 ID로 설정하고 이 요소들에 값을 입력을 계산하는데 기여한다.(또는 다른 효과)</td> + </tr> + </tbody> +</table> + +<h3 id="form이_사용되는_일반적인_form_구조" style="line-height: 24px;">form이 사용되는 일반적인 form 구조</h3> + +<p>HTML 폼의 지정된 구조를 넘어서 하나의 HTML이라고 생각 하는게 좋다. T 이 의미는 HTML 폼을 구성하는데 HTML의 모든 능력을 사용할 수 있다는 것이다.</p> + +<p>예제에서 볼 수 있드니 라벨과 위젯을 둘러싸는데 최고의 방법은 {{HTMLElement("p")}}요소 나 {{HTMLElement("div")}}요소를 사용하는 것이다.</p> + +<p>게다가 {{HTMLElement("fieldset")}} 요소에 HTML 타이틀을 사용하고 복잡한 폼을 만드는데 구조에 섹션을 사용하는것도 일반적인 관행이다.</p> + +<p>HTML 목록은 체크박스나 라디오 버튼을 사용하는데 일반적으로 사용된다.</p> + +<p>간단한 지불 폼을 만들어 보자</p> + +<pre class="brush:html;" style="font-size: 14px;"><form> + <h1>Payment form</h1> + <p>Required fields are followed by <strong><abbr title="required">*</abbr></strong>.</p> + + <section> + <h2>Contact information</h2> + + <fieldset> + <legend>Title</legend> + <ul> + <li> + <label for="title_1"> + <input type="radio" id="title_1" name="title" value="M." /> + Mister + </label> + </li> + <li> + <label for="title_2"> + <input type="radio" id="title_2" name="title" value="Ms." /> + Miss + </label> + </li> + </ul> + </fieldset> + + <p> + <label for="name"> + <span>Name: </span> + <input type="text" id="name" name="username" required /> + <strong><abbr title="required">*</abbr></strong> + </label> + </p> + + <p> + <label for="mail"> + <span>E-mail: </span> + <input type="email" id="mail" name="usermail" required /> + <strong><abbr title="required">*</abbr></strong> + </label> + </p> + </section> + + <section> + <h2>Payment information</h2> + + <p> + <label for="card"> + <span>Card type:</span> + <select id="card" name="usercard"> + <option value="visa">Visa</option> + <option value="mc">Mastercard</option> + <option value="amex">American Express</option> + </select> + </label> + </p> + <p> + <label for="number"> + <span>Card number:</span> + <input type="text" id="number" name="cardnumber" required /> + <strong><abbr title="required">*</abbr></strong> + </label> + </p> + <p> + <label for="date"> + <span>Expiration date:</span> + <input type="text" id="date" name="expiration" required /> + <strong><abbr title="required">*</abbr></strong> + <em>formated as mm/yy</em> + </label> + </p> + </section> + + <section> + <p> + <button>Validate the payment</button> + </p> + </section> +</form></pre> + +<p>See this form in action (with a touch of CSS):</p> + +<p>{{EmbedLiveSample("A_payment_form","100%",620, "", "Learn/HTML/Forms/How_to_structure_an_HTML_form/Example")}}</p> + +<h2 id="HTML_위젯" style="line-height: 30px;">HTML 위젯</h2> + +<p>When you build a form, you need to use some widgets to collect data from the user. In this article we will see how to display those widgets; if you want to know more about the way those widgets work, it is detailed in the article: <a href="/en-US/docs/HTML/Forms/The_native_form_widgets" title="/en-US/docs/HTML/Forms/The_native_form_widgets">The native form widgets</a>.</p> + +<h3 id="The_<input>_element" style="line-height: 24px;">The <input> element</h3> + +<p>이 요소는 거의 모든 것을 할 있기 떄문에 특별 한 종류이다. 간단하게 type속성을 설정하여 완전히 바뀔수 있다. 간단하게 하기 위해서 type속성의 값을 4가지로 분류하였다. 단일 라인 텍스트 필드, 텍스트 입력 없는 컨트롤, 시간이나 날짜 컨트롤, 버튼. <span style="line-height: 1.5;">이와 같은 다형성 떄문에 {{HTMLElement("input")}} 요소는 많은 속성을 지원하지만 type 속성값에 따라 달라지기 떄문에 어느 속성이 적절한지, 어느 것이 필요한지 선택하는 것은 어려울 수 있다. </span></p> + +<p>This is all summarized in the following table (for a full list of all attributes, visit the page for the {{HTMLElement("input")}} element):</p> + +<table> + <thead> + <tr> + <th scope="col">type 속성 의 값</th> + <th scope="col">설명</th> + <th scope="col">필수 속성</th> + <th scope="col">관련된 속성</th> + </tr> + </thead> + <tbody> + <tr> + <th colspan="4" style="text-align: center;">단일 선 텍스트 필드</th> + </tr> + <tr> + <td><code>text</code></td> + <td>이것은 가장 기본적인 텍스트 필드이다. type속성을 위한 텍스트 값은 이 속성의 기본 값이다.(자동 유효성 검사를 하지않음)</td> + <td> </td> + <td>{{htmlattrxref("autocomplete","input")}}, {{htmlattrxref("list","input")}}, {{htmlattrxref("maxlength","input")}}, {{htmlattrxref("pattern","input")}}, {{htmlattrxref("placeholder","input")}}, {{htmlattrxref("readonly","input")}}, {{htmlattrxref("required","input")}}, {{htmlattrxref("size","input")}}, {{htmlattrxref("spellcheck","input")}}</td> + </tr> + <tr> + <td><code>email</code></td> + <td>하나 또는 여러개 이메일 주소를 작성하기 위해 사용되는 필드</td> + <td> </td> + <td>{{htmlattrxref("autocomplete","input")}}, {{htmlattrxref("list","input")}}, {{htmlattrxref("maxlength","input")}}, {{htmlattrxref("multiple","input")}}, {{htmlattrxref("pattern","input")}}, {{htmlattrxref("placeholder","input")}}, {{htmlattrxref("readonly","input")}}, {{htmlattrxref("required","input")}}, {{htmlattrxref("size","input")}}</td> + </tr> + <tr> + <td><code>password</code></td> + <td>텍스트 필드의 값을 가리기 위해 사용되는 텍스트 필드</td> + <td> </td> + <td>{{htmlattrxref("autocomplete","input")}}, {{htmlattrxref("list","input")}}, {{htmlattrxref("maxlength","input")}}, {{htmlattrxref("readonly","input")}}, {{htmlattrxref("required","input")}}, {{htmlattrxref("size","input")}}</td> + </tr> + <tr> + <td><code>search</code></td> + <td>검색 하기 위한 텍스트 필드</td> + <td> </td> + <td>{{htmlattrxref("autocomplete","input")}}, {{htmlattrxref("autosave","input")}}, {{htmlattrxref("list","input")}}, {{htmlattrxref("maxlength","input")}}, {{htmlattrxref("pattern","input")}}, {{htmlattrxref("placeholder","input")}}, {{htmlattrxref("readonly","input")}}, {{htmlattrxref("required","input")}}, {{htmlattrxref("size","input")}}, {{htmlattrxref("spellcheck","input")}}</td> + </tr> + <tr> + <td><code>tel</code></td> + <td>전화 번호를 입력할 수 있는 텍스트 필드</td> + <td> </td> + <td>{{htmlattrxref("autocomplete","input")}}, {{htmlattrxref("list","input")}}, {{htmlattrxref("maxlength","input")}}, {{htmlattrxref("pattern","input")}}, {{htmlattrxref("placeholder","input")}}, {{htmlattrxref("readonly","input")}}, {{htmlattrxref("required","input")}}, {{htmlattrxref("size","input")}}</td> + </tr> + <tr> + <td><code>url</code></td> + <td>절대 URL을 다루기 위한 필드</td> + <td> </td> + <td>{{htmlattrxref("autocomplete","input")}}, {{htmlattrxref("list","input")}}, {{htmlattrxref("maxlength","input")}}, {{htmlattrxref("pattern","input")}}, {{htmlattrxref("placeholder","input")}}, {{htmlattrxref("readonly","input")}}, {{htmlattrxref("required","input")}}, {{htmlattrxref("size","input")}}</td> + </tr> + <tr> + <th colspan="4" style="text-align: center;">텍스트 입력 없는 컨트롤</th> + </tr> + <tr> + <td><code>checkbox</code></td> + <td>체크박스</td> + <td> </td> + <td>{{htmlattrxref("checked","input")}}, {{htmlattrxref("required","input")}}</td> + </tr> + <tr> + <td><code>color</code></td> + <td>색상을 입력 받기위한 필드</td> + <td> </td> + <td>{{htmlattrxref("autocomplete","input")}}, {{htmlattrxref("list","input")}}, {{htmlattrxref("required","input")}}</td> + </tr> + <tr> + <td><code>file</code></td> + <td>A control that lets the user select a file.</td> + <td> </td> + <td>{{htmlattrxref("accept","input")}}, {{htmlattrxref("multiple","input")}}, {{htmlattrxref("required","input")}}</td> + </tr> + <tr> + <td><code>hidden</code></td> + <td>보여주지 않는 컨트롤 이지만 서버로 전송되는 필드</td> + <td> </td> + <td> </td> + </tr> + <tr> + <td><code>number</code></td> + <td>소숫점을 입력받는 컨트롤</td> + <td> </td> + <td>{{htmlattrxref("autocomplete","input")}}, {{htmlattrxref("list","input")}}, {{htmlattrxref("max","input")}}, {{htmlattrxref("min","input")}}, {{htmlattrxref("readonly","input")}}, {{htmlattrxref("required","input")}}, {{htmlattrxref("step","input")}}</td> + </tr> + <tr> + <td><code>radio</code></td> + <td>라디오 버튼. 그룹 중 한가지만 선택하기 위한 필드</td> + <td> </td> + <td>{{htmlattrxref("checked","input")}}, {{htmlattrxref("required","input")}}</td> + </tr> + <tr> + <td><code>range</code></td> + <td>정확하지 않는 숫자를 입력받기 위한 필드</td> + <td> </td> + <td>{{htmlattrxref("autocomplete","input")}}, {{htmlattrxref("list","input")}}, {{htmlattrxref("max","input")}}, {{htmlattrxref("min","input")}}, {{htmlattrxref("required","input")}}, {{htmlattrxref("step","input")}}</td> + </tr> + <tr> + <th colspan="4" style="text-align: center;">시간 과 날짜 컨트롤</th> + </tr> + <tr> + <td><code>date</code></td> + <td>(년, 원, 일)날짜를 입력 받을 수 잇는 컨트롤</td> + <td> </td> + <td>{{htmlattrxref("autocomplete","input")}}, {{htmlattrxref("list","input")}}, {{htmlattrxref("max","input")}}, {{htmlattrxref("min","input")}}, {{htmlattrxref("readonly","input")}}, {{htmlattrxref("required","input")}}</td> + </tr> + <tr> + <td><code>datetime</code></td> + <td>UTC 타임 존 기반으로 전체 날짜와 시간(시간, 분, 초 )을 입력 받기 위한 필드</td> + <td> </td> + <td>{{htmlattrxref("autocomplete","input")}}, {{htmlattrxref("list","input")}}, {{htmlattrxref("max","input")}}, {{htmlattrxref("min","input")}}, {{htmlattrxref("readonly","input")}}, {{htmlattrxref("required","input")}}</td> + </tr> + <tr> + <td><code>datetime-local</code></td> + <td>타임존 기반이 아닌 날짜와 시간을 입력받기 위한 컨트롤</td> + <td> </td> + <td>{{htmlattrxref("autocomplete","input")}}, {{htmlattrxref("list","input")}}, {{htmlattrxref("max","input")}}, {{htmlattrxref("min","input")}}, {{htmlattrxref("readonly","input")}}, {{htmlattrxref("required","input")}}</td> + </tr> + <tr> + <td><code>month</code></td> + <td>타임존 기반이 아닌 달과 년도를 입력 받기 위한 컨트롤</td> + <td> </td> + <td>{{htmlattrxref("autocomplete","input")}}, {{htmlattrxref("list","input")}}, {{htmlattrxref("max","input")}}, {{htmlattrxref("min","input")}}, {{htmlattrxref("readonly","input")}}, {{htmlattrxref("required","input")}}</td> + </tr> + <tr> + <td><code>time</code></td> + <td>타임존 기반이 아닌 시간을 입력 받기 위한 컨트롤</td> + <td> </td> + <td>{{htmlattrxref("autocomplete","input")}}, {{htmlattrxref("list","input")}}, {{htmlattrxref("max","input")}}, {{htmlattrxref("min","input")}}, {{htmlattrxref("readonly","input")}}, {{htmlattrxref("required","input")}}</td> + </tr> + <tr> + <td><code>week</code></td> + <td>타임존 기반이 아닌 전체 날짜를 일주일-년도 숫자로 주 번호를 입력하는 컨트롤</td> + <td> </td> + <td>{{htmlattrxref("autocomplete","input")}}, {{htmlattrxref("list","input")}}, {{htmlattrxref("max","input")}}, {{htmlattrxref("min","input")}}, {{htmlattrxref("readonly","input")}}, {{htmlattrxref("required","input")}}</td> + </tr> + <tr> + <th colspan="4" style="text-align: center;">버튼</th> + </tr> + <tr> + <td><code>button</code></td> + <td>기본 행동이 없는 누르는 버튼</td> + <td> </td> + <td>{{htmlattrxref("formaction","input")}}, {{htmlattrxref("formenctype","input")}}, {{htmlattrxref("formmethod","input")}}, {{htmlattrxref("formnovalidate","input")}}, {{htmlattrxref("formtarget","input")}}</td> + </tr> + <tr> + <td><code>image</code></td> + <td>그래픽적인 전송버튼</td> + <td>{{htmlattrxref("src","input")}}, {{htmlattrxref("alt","input")}}</td> + <td>{{htmlattrxref("width","input")}}, {{htmlattrxref("height","input")}}, {{htmlattrxref("formaction","input")}}, {{htmlattrxref("formenctype","input")}}, {{htmlattrxref("formmethod","input")}}, {{htmlattrxref("formnovalidate","input")}}, {{htmlattrxref("formtarget","input")}}</td> + </tr> + <tr> + <td><code>reset</code></td> + <td>폼의 내용을 초기화 하는 컨트롤</td> + <td> </td> + <td>{{htmlattrxref("formaction","input")}}, {{htmlattrxref("formenctype","input")}}, {{htmlattrxref("formmethod","input")}}, {{htmlattrxref("formnovalidate","input")}}, {{htmlattrxref("formtarget","input")}}</td> + </tr> + <tr> + <td><code>submit</code></td> + <td>폼을 전송하는 버튼</td> + <td> </td> + <td>{{htmlattrxref("formaction","input")}}, {{htmlattrxref("formenctype","input")}}, {{htmlattrxref("formmethod","input")}}, {{htmlattrxref("formnovalidate","input")}}, {{htmlattrxref("formtarget","input")}}</td> + </tr> + </tbody> +</table> + +<p><span style="line-height: 1.5;">몇가지 이유 때문에 브라우저에서 특정 type 속성의 값 설정을 지원하지 않으면 {{HTMLElement("input")}} 요소는 text 속성으로 렌더링 한다. </span>이것은 매력적이지 않아도 어쩔 수없이 폼이 작동하도록 한다.</p> + +<p>요소는 강력한 도구지만, 모든 것을 할수 없고 다른 것들을 다루기 위해 다른 요소들이 있다.</p> + +<h3 id="<textarea>_요소" style="line-height: 24px;"><textarea> 요소</h3> + +<p>이 요소는 다중 텍스트 필드로 설정된다. 이 요소는 사용자가 입력한 텍스트에 줄 바꿈을 할수 있다는 것을 제외하고 단일 라인 텍스트 필드와 정확하게 똑같이 작동한다. 또한 여러줄에 걸처 랜더링을 제어 하기위해 몇가지 추가 속성 설정을 허락한다.</p> + +<table> + <caption> {{HTMLElement("textarea")}} 요소 속성</caption> + <thead> + <tr> + <th scope="col">Attribute name</th> + <th scope="col">기본값</th> + <th scope="col">설명</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{htmlattrxref("cols","textarea")}}</td> + <td><code>20</code></td> + <td>보여지는 문자 너비의 평균을 기준으로 텍스트 컨트롤의 너비</td> + </tr> + <tr> + <td>{{htmlattrxref("rows","textarea")}}</td> + <td> </td> + <td>보여지는 텍스트 행의 수</td> + </tr> + <tr> + <td>{{htmlattrxref("wrap","textarea")}}</td> + <td><code>soft</code></td> + <td>hard, soft 이 둘중 하나의 값으로 어떻게 텍스트를 둘러쌀것인지 나타낸다.</td> + </tr> + </tbody> +</table> + +<p> {{HTMLElement("textarea")}} 요소는 {{HTMLElement("input")}} 요소와 다르게 작동한다. {{HTMLElement("input")}} 요소는 자동으로 닫히는 요소이다. 이는 자식 요소를 가질 수 없다는 것을 의미한다. 이와 반대로 요소는 text 콘텐츠를 자식으로 가질 수 있는 일반적인 요소이다.</p> + +<p>이는 두가지 영향이 있다.</p> + +<ul> + <li>만약 {{HTMLElement("input")}}요소에 기본값을 정의하기 원한다면, value 속성을 사용하여 지정해야 되나, {{HTMLElement("textarea")}}요소에서는 기본값을 {{HTMLElement("textarea")}} 태그 사이에 넣기만 하면된다.</li> + <li>자연스러움 때문에 {{HTMLElement("textarea")}} 요소는 오직 텍스트 콘텐츠만 받아들인다. 이 의미는 어떠한 HTML콘텐츠도 {{HTMLElement("textarea")}} 요소에 넣으면 텍스트 콘텐츠로 렌더링 된다.</li> +</ul> + +<p> 예제를 따라가면 다음 두 요소는 똑같이 랜더링 되어 질것이다.</p> + +<pre class="brush:html;" style="font-size: 14px;"><form> + <p> + <label for="text_1">With regular HTML</label><br> + <textarea id="text_1" name="regular"><p>I'm a paragraphe</p></textarea> + </p> + <p> + <label for="text_2">With escaped HTML</label><br> + <textarea id="text_2" name="escaped">&lt;p&gt;I'm a paragraphe&lt;/p&gt;</textarea> + </p> + <p> + <button>Send me</button> + </p> +</form></pre> + +<h3 id="<select>_<option>그리고_<optgroup>_요소" style="line-height: 24px;"><select>, <option>그리고 <optgroup> 요소</h3> + +<p>요소는 선택 박스를 만들 수 있게 해준다(떄로는 콤보 박스라고 한다). 선택 박스는 사용자가 하나 이상 미리 정의 된 값을 선택하는 위젯이다. 단일 값 선택 박스와 다중 값 선택 박스는 다르다. 이에 대한 자세한 내용은 다음 문서를 확인해라 <a href="/en-US/docs/HTML/Forms/The_native_form_widgets" title="/en-US/docs/HTML/Forms/The_native_form_widgets">The native form widgets</a>.</p> + +<p>선택 박스 안의 값들은 {{HTMLElement("option")}} 요소에서 정의되고 {{HTMLElement("optgroup")}} 요소 안에서 그룹화 될 수 있다.</p> + +<p>Let's take an example:</p> + +<pre class="brush:html;" style="font-size: 14px;"><form> + <p> + <label for="myFruit">Pick a fruit</label> + <select id="myFruit" name="fruit"> + <!-- There is a trick here you think you'll pick + a banana but you'll eat an orange >:-) --> + <option value="orange">Banana</option> + <option>Cherry</option> + <optgroup label="berries"> + <option>Blueberry</option> + <option>Raspberry</option> + <option>Strawberry</option> + </optgroup> + </select> + </p> +</form></pre> + +<p><span style="line-height: 1.5;">{HTMLElement("option")}} 요소는 폼이 전송되면 전송될 value속성을 설정한다.</span> <span style="line-height: 1.5;">만약 value 속성을 바뜨리면 {{HTMLElement("option")}} 요소는 value 값을 선택 박스 값으로 사용된다.</span></p> + +<p><span style="line-height: 1.5;">{{HTMLElement("optgroup")}} 요소의 라벨 속성은 값이 나오기전에 보여주고 옵션 같은 요소들은 선택할 수 없게 나온다.</span>.</p> + +<table> + <caption>{{HTMLElement("option")}} 요소 의 속성</caption> + <thead> + <tr> + <th scope="col">속성 이름</th> + <th scope="col">기본값</th> + <th scope="col">설명</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{htmlattrxref("label","option")}}</td> + <td> </td> + <td>이 속성은 옵션을 설명하는 라벨의 텍스트이다. 만약 라벨 속성이 정의되지 않으면 이 값은 요소의 텍스트 콘텐츠로 설정된다.</td> + </tr> + <tr> + <td>{{htmlattrxref("selected","option")}}</td> + <td>(<em>false</em>)</td> + <td>만약 이 속성이 불리언 값으로 설정되는 경우 처음에 선택된 상태로 시작하게된다.</td> + </tr> + </tbody> +</table> + +<table> + <caption>Attributes for the {{HTMLElement("optgroup")}} element</caption> + <thead> + <tr> + <th scope="col">Attribute name</th> + <th scope="col">Default value</th> + <th scope="col">Description</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{htmlattrxref("label","optgroup")}}</td> + <td> </td> + <td>The name of the group of options. <strong>This attribute is mandatory.</strong></td> + </tr> + </tbody> +</table> + +<h3 id="<datalist>요소" style="line-height: 24px;"><datalist>요소 </h3> + +<p>이 요소는 기존에 있는 위젯들에 사전 설정 값을 제공 함으로써 위젯들을 확장시킨다. 가장 잘 알려진 사용 방법은 텍스트 필드의 자동 완성 목록이다. 값들은 {{HTMLElement("datalist")}} 요소 안에 있는 {{HTMLElement("option")}}요소의 값으로 사용할 수 있다.</p> + +<p>{{HTMLElement("datalist")}}요소와 바인드 하기위해서는 사용하는 요소의 list속성을 이용하여 설정해야한다. 이 속성은 {{HTMLElement("datalist")}} 요소의 id로 설정된다.</p> + +<p>요소는 최근에 HTML 폼으로 추가 되었다. 그러므로 아직 이를 지원하지 않는 브라우저들도 있다. 이 문제를 처리하기 위하여 아래에 약간 까다로운 예제가 있다.</p> + +<pre class="brush:html;" style="font-size: 14px;"><form> + <p> + <label for="myFruit">What is your favorite fruit?</label> + <input type="text" id="myFruit" name="fruit" list="fruitList" /> + + <datalist id="fruitList"> + <label for="suggestion">or pick a fruit</label> + <select id="suggestion" name="altFruit"> + <option value="banana">Banana</option> + <option value="cherry">Cherry</option> + <option value="strawberry">Strawberry</option> + </select> + </datalist> + </p> +</form></pre> + +<p>한편 {{HTMLElement("datalist")}} 요소를 지원하는 브라우저는 {{HTMLElement("option")}} 요소를 무시하고 이를 사용하는 요소를 확장 할 것이다. 이와 반대로 {{HTMLElement("datalist")}} 요소를 지원하지 않는 브라우저는 라벨과 선택 박스를 표시 할 것이다. 물론 {{HTMLElement("datalist")}} 요소를 지원하지 않는 브라우저에 대해 자바스크립트로 하는 다른 방법이 있지만 항상 자바스크립트만 사용하는 것은 좋은 것이 아니다.</p> + +<table> + <tbody> + <tr> + <th scope="row">Safari 6</th> + <td><img alt="Screenshot of the datalist element fallback with Safari on Mac OS" src="/files/4583/datalist-safari.png" style="height: 32px; width: 495px;"></td> + </tr> + <tr> + <th scope="row">Firefox 18</th> + <td><img alt="Screenshot of the datalist element with Firefox on Mac OS" src="/files/4581/datalist-firefox-macos.png" style="height: 102px; width: 353px;"></td> + </tr> + </tbody> +</table> + +<h3 id="<meter>_와_<progress>_요소들" style="line-height: 24px;"><meter> 와 <progress> 요소들 </h3> + +<p>이 두요소는 그래픽적으로 숫자 값을 표현 하는방법이다. 이 두 요소의 차이점은 두 요소의 의미가 다르다는 것이다.</p> + +<ul> + <li>{{HTMLElement("meter")}} 요소는 정적인 값을 최소와 최대 값사이에 상대적인 위치를 나타낸다</li> + <li>The {{HTMLElement("progress")}} 요소는 최소와 최대값을 시간에 따라 바뀌는 가변적인 값을 나타낸다. 값이 변하면 자바스크립트를 이용하여 다룰수 있다는것을 주목할 필요가 있다. 요소 자신은 값을 변화시키기 위한 어떠한 매커니즘도 가지고 있지 않다.</li> +</ul> + +<p>속성으로 인해 이 요소들은 다음 속성을 지정 가능하다.</p> + +<p><br> + <strong style="font-style: inherit; font-weight: bold; line-height: 1.5;">{{HTMLElement("meter")}} 요소는 다음과 같은 속성을 가진다</strong></p> + +<table> + <thead> + <tr> + <th scope="col">Attribute name</th> + <th scope="col">Default value</th> + <th scope="col">Description</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{htmlattrxref("min","meter")}}</td> + <td>0</td> + <td>The lower numeric bound of the measured range.</td> + </tr> + <tr> + <td>{{htmlattrxref("max","meter")}}</td> + <td>1</td> + <td>The upper numeric bound of the measured range.</td> + </tr> + <tr> + <td>{{htmlattrxref("low","meter")}}</td> + <td>the <code>min</code> value</td> + <td>The upper numeric bound of the low end of the measured range.</td> + </tr> + <tr> + <td>{{htmlattrxref("high","meter")}}</td> + <td>the <code>max</code> value</td> + <td>The lower numeric bound of the high end of the measured range.</td> + </tr> + <tr> + <td>{{htmlattrxref("optimum","meter")}}</td> + <td> </td> + <td>The optimal numeric value.</td> + </tr> + </tbody> +</table> + +<table> + <caption>Attributes for the {{HTMLElement("progress")}} element</caption> + <thead> + <tr> + <th scope="col">Attribute name</th> + <th scope="col">Default value</th> + <th scope="col">Description</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{htmlattrxref("max","progress")}}</td> + <td> </td> + <td>This attribute describes how much work the task indicated by the {{HTMLElement("progress")}} element requires before it's complete.</td> + </tr> + </tbody> +</table> + +<h3 id="The_<button>_element" style="line-height: 24px;">The <button> element </h3> + +<p>{{HTMLElement("button")}} 요소는 폼 버튼을 만드는 가장 쉬운 방법이다. <span style="line-height: 1.5;">버튼은 type속성에 따라 3가지 타입을 가진다.</span></p> + +<ul> + <li>전송 버튼은 폼 데이터들을 {{HTMLElement("form")}}요소에 action 속성에 정의 된 웹 페이지에 보낸다.</li> + <li>리셋 버튼은 폼의 모든 위젯들을 기본 값으로 재설정한다. 폼 사용자 경험 관점에서 이 버튼을 사용하는것은 좋지 않은 사례로 간주되고 이를 피해야 한다. 이것은 사용자가 단순히 실수로 한것이 모든 작업을 잃게 할 수 있다.</li> + <li>익명 버튼은 어떠한 의미도 없는 대신 자바스크립트를 이용하여 다룰 수 있다..</li> +</ul> + +<p><br> + <strong style="font-style: inherit; font-weight: bold; line-height: 1.5;">{HTMLElement("button")}} 요소의 속성</strong></p> + +<table> + <thead> + <tr> + <th scope="col">속성 이름</th> + <th scope="col">기본값</th> + <th scope="col">설명</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{htmlattrxref("type","button")}}</td> + <td><code>submit</code></td> + <td>버튼의 타입. <code>button</code>, <code>reset</code>, <code>submit 이 있다.</code></td> + </tr> + <tr> + <td>{{htmlattrxref("formaction","button")}}</td> + <td> </td> + <td>만약 버튼이 submit 버튼이면 이 속성은 {{HTMLElement("form")}}요소의 action 속성에 오버라이드 된다.</td> + </tr> + <tr> + <td>{{htmlattrxref("formenctype","button")}}</td> + <td> </td> + <td>만약 버튼이 submit 버튼이면 이 속성은 {{HTMLElement("form")}}요소의 enctype 속성에 오버라이드 된다.</td> + </tr> + <tr> + <td>{{htmlattrxref("formmethod","button")}}</td> + <td> </td> + <td>만약 버튼이 submit 버튼이면 이 속성은 {{HTMLElement("form")}}요소의 method 속성에 오버라이드 된다.</td> + </tr> + <tr> + <td>{{htmlattrxref("formnovalidate","button")}}</td> + <td> </td> + <td>만약 버튼이 submit 버튼이면 이 속성은 {{HTMLElement("form")}}요소의 novalidate 속성에 오버라이드 된다.</td> + </tr> + <tr> + <td>{{htmlattrxref("formtarget","button")}}</td> + <td> </td> + <td>만약 버튼이 submit 버튼이면 이 속성은 {{HTMLElement("form")}}요소의 target 속성에 오버라이드 된다.</td> + </tr> + </tbody> +</table> + +<p>기술적으로 말하면 {{HTMLElement("button")}} 요소와 {{HTMLElement("input")}} 요소의 속성에 정의된 버튼 요소는 거의 차이가 없다. 단 한가지 차이점은 버튼 자체의 라벨 이다.요소 안에서는 라벨은 오직 문자 데이터로만 나타 낼 수 있지만 {{HTMLElement("button")}} 요소에서는 어떠한 HTML이 될 수있다. 그래서 이에 따른 스타일을 디자인 할 수있다.</p> + +<div class="note"><strong>Note:</strong> For historical reasons, the {{HTMLElement("button")}} element wasn't used very often and in many forms developers preferred to use buttons made with the {{HTMLElement("input")}} element. This is due to a bug in legacy versions of Internet Explorer (IE). In IE6 and IE7, if you add a <code>name</code> and a <code>value</code> attribute to a {{HTMLElement("button")}} element, they do not send the content of the <code>value</code> attribute but the raw content of the button instead. This has been fixed since IE8, so there is no longer any reason to avoid using the {{HTMLElement("button")}} element.</div> + +<div class="note"> </div> + +<h3 id="공통_속성" style="line-height: 24px;">공통 속성</h3> + +<p>Many of the elements used to define form widgets have some their own attributes. However, there is a set of attributes common to all form elements that give you some control over those widgets. Here is a list of those common attributes:</p> + +<table> + <thead> + <tr> + <th scope="col">Attribute name</th> + <th scope="col">Default value</th> + <th scope="col">Description</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>autofocus</code></td> + <td>(<em>false</em>)</td> + <td>This Boolean attribute lets you specify that the element should automatically have input focus when the page loads, unless the user overrides it, for example by typing in a different control. Only one form-associated element in a document can have this attribute specified.</td> + </tr> + <tr> + <td><code>disabled</code></td> + <td>(<em>false</em>)</td> + <td>This Boolean attribute indicates that the user cannot interact with the element. If this attribute is not specified, the element inherits its setting from the containing element, for example {{HTMLElement("fieldset")}}; if there is no containing element with the <code>disabled</code> attribute set, then the element is enabled.</td> + </tr> + <tr> + <td><code>form</code></td> + <td> </td> + <td>The form element that the widget is associated with. The value of the attribute must be the <code>id</code> attribute of a {{HTMLElement("form")}} element in the same document. In theory, it lets you set a form widget outside of a {{HTMLElement("form")}} element. In practice, however, there is no browser which supports that feature.</td> + </tr> + <tr> + <td><code>name</code></td> + <td> </td> + <td>The name of the element; this is submitted with the form data.</td> + </tr> + <tr> + <td><code>value</code></td> + <td> </td> + <td>The element's initial value.</td> + </tr> + </tbody> +</table> + +<h2 id="Using_ARIA_to_structure_HTML_forms" style="line-height: 30px;">Using <a href="/en-US/docs/Accessibility/ARIA" title="/en-US/docs/Accessibility/ARIA">ARIA</a> to structure HTML forms</h2> + +<p><a href="/en-US/docs/Accessibility/ARIA" title="/en-US/docs/Accessibility/ARIA">ARIA</a> is <a href="http://www.w3.org/TR/wai-aria/" rel="external" title="http://www.w3.org/TR/wai-aria/">a W3C Candidate Recommendation</a> which adds to HTML improved accessibility for rich Internet applications, including for forms. We will discuss its use in more detail in the "<a href="/en-US/docs/HTML/Forms/How_to_build_custom_form_widgets" title="/en-US/docs/HTML/Forms/How_to_build_custom_form_widgets">How to build custom form widgets</a>" article, but there are some basics that are good to know.</p> + +<p>Before going further, it's worth noting that support for ARIA and assistive technologies among browsers is far from perfect, but it's improving. Just to understand the issue, when a browser encounters an ARIA attribute, it has to send information to the operating system's accessibility layer. Not all browsers are good at doing this cross platform. The assistive technologies, on their own, have to connect themselves to the OS accessibility layer to handle the information that comes from the browsers. Surprisingly, not all assistive technologies do it well. So using ARIA does not mean that your web application will be accessible, but it means that you do your best to achieve this. Unfortunately, for the time being, ARIA remains a best effort technology, but it's always better than nothing.</p> + +<p>If you want to dig into using ARIA with HTML forms, feel free to <a href="/en-US/docs/Accessibility/ARIA/forms" title="/en-US/docs/Accessibility/ARIA/forms">read the related section in the ARIA documentation</a>.</p> + +<h3 id="The_aria-labelledby_attribute" style="line-height: 24px;">The <a href="/en-US/docs/Accessibility/ARIA/ARIA_Techniques/Using_the_aria-labelledby_attribute" title="/en-US/docs/Accessibility/ARIA/ARIA_Techniques/Using_the_aria-labelledby_attribute"><code>aria-labelledby</code></a> attribute</h3> + +<p>This attribute is a convenient way to define a label without using the {{HTMLElement("label")}} element. The attribute is set on the widget element and references the <code>id</code> attribute of the element to use as a label.</p> + +<pre class="brush:html;" style="font-size: 14px;"><form> + <p id="fruitLabel">What's your favorite fruit</p> + <p> + <input type="text" name="fruit" aria-labelledby="fruitLabel"> + </p> +</form></pre> + +<p>Conceptually, it's the opposite of the <code>for</code> attribute on the {{HTMLElement("label")}} element. With the <code>for</code> attribute, you reference the <code>id</code> of the widget but with the <code>aria-labbeldby</code> attribute, you reference the <code>id</code> of the label.</p> + +<h3 id="The_aria-describedby_attribute" style="line-height: 24px;">The <a href="/en-US/docs/Accessibility/ARIA/ARIA_Techniques/Using_the_aria-describedby_attribute" title="/en-US/docs/Accessibility/ARIA/ARIA_Techniques/Using_the_aria-describedby_attribute"><code>aria-describedby</code></a> attribute</h3> + +<p>This attribute works like the <code>aria-labelledby</code> attribute. The difference is mainly semantic. A label defines the essence of an object, while a description provides more information that the user might need. This attribute is not advised for form elements, you should rely on the <code>aria-labelledby</code> attribute, except if you want to provide extensive information on the current form element. It is to be used as a provider for a longer description.</p> + +<h3 id="The_aria-label_attribute" style="line-height: 24px;">The <a href="/en-US/docs/Accessibility/ARIA/ARIA_Techniques/Using_the_aria-label_attribute" title="/en-US/docs/Accessibility/ARIA/ARIA_Techniques/Using_the_aria-label_attribute"><code>aria-label</code></a> attribute</h3> + +<p>This attribute is used when there is no explicit label in the DOM for a given widget. It lets you provide a widget that will be passed to assitive technologies without actually creating a DOM node for it.</p> + +<pre class="brush:html;" style="font-size: 14px;"><form> + <p> + <input type="search" name="q" aria-label="Search" /> + <input type="submit" value="Go" /> + </p> +</form></pre> + +<h3 id="The_role_attribute" style="line-height: 24px;">The <a href="/en-US/docs/Accessibility/ARIA/ARIA_Techniques" title="/en-US/docs/Accessibility/ARIA/ARIA_Techniques"><code>role</code></a> attribute</h3> + +<p>This is the most important ARIA attribute. It lets you give specific semantic information, understandable by assitive technologies, for a given HTML element. There are many roles available and some of them are dedicated to form widgets.</p> + +<p>ARIA tries to provide semantics for widgets that are not currently available in HTML as well as for elements that already exist. We will see in detail how to use those roles in the article: How to build custom form widgets.</p> + +<p>Those roles for form widgets are :</p> + +<ul> + <li><a href="/en-US/docs/Accessibility/ARIA/ARIA_Techniques/Using_the_button_role" title="/en-US/docs/Accessibility/ARIA/ARIA_Techniques/Using_the_button_role">Button</a></li> + <li><a href="/en-US/docs/Accessibility/ARIA/ARIA_Techniques/Using_the_checkbox_role" title="/en-US/docs/Accessibility/ARIA/ARIA_Techniques/Using_the_checkbox_role">Checkbox</a></li> + <li><a href="/en-US/docs/Accessibility/ARIA/ARIA_Techniques/Using_the_progressbar_role" title="/en-US/docs/Accessibility/ARIA/ARIA_Techniques/Using_the_progressbar_role">Progressbar</a></li> + <li>Radio</li> + <li><a href="/en-US/docs/Accessibility/ARIA/ARIA_Techniques/Using_the_slider_role" title="/en-US/docs/Accessibility/ARIA/ARIA_Techniques/Using_the_slider_role">Slider</a></li> + <li>Spinbutton</li> + <li><a href="/en-US/docs/Accessibility/ARIA/ARIA_Techniques/Using_the_textbox_role" title="/en-US/docs/Accessibility/ARIA/ARIA_Techniques/Using_the_textbox_role">textbox</a></li> +</ul> + +<p>It's also worth noting that there's something called a composite role:</p> + +<ul> + <li><a href="/en-US/docs/Accessibility/ARIA/ARIA_Techniques/Using_the_listbox_role" title="/en-US/docs/Accessibility/ARIA/ARIA_Techniques/Using_the_listbox_role">Listbox</a></li> + <li>Radiogroup</li> +</ul> + +<p>If those roles are extremely useful, know that <a href="/en-US/docs/Accessibility/ARIA/ARIA_Techniques" title="/en-US/docs/Accessibility/ARIA/ARIA_Techniques">there are more</a>; ARIA is a very large specification. Digging into it can help you improve accessibility in areas far afield from HTML forms.</p> + +<h2 id="결론" style="line-height: 30px;">결론</h2> + +<p>You now have all the knowledge to properly structure your HTML forms; the next article will dig into implementation details and functional expectations: <a href="/en-US/docs/HTML/Forms/The_native_form_widgets" title="/en-US/docs/HTML/Forms/The_native_form_widgets">The native form widgets</a>.</p> + +<h2 id="볼거리" style="line-height: 30px;">볼거리</h2> + +<ul> + <li><a href="http://www.alistapart.com/articles/sensibleforms/" rel="external" title="http://www.alistapart.com/articles/sensibleforms/">A List Apart: <em>Sensible Forms: A Form Usability Checklist</em></a></li> +</ul> diff --git a/files/ko/learn/html/forms/index.html b/files/ko/learn/html/forms/index.html new file mode 100644 index 0000000000..f7244cbdc1 --- /dev/null +++ b/files/ko/learn/html/forms/index.html @@ -0,0 +1,358 @@ +--- +title: HTML 폼 가이드 +slug: Learn/HTML/Forms +translation_of: Learn/Forms +--- +<p><span class="seoSummary">이 가이드는 HTML 폼을 숙달 시키는데 도움이 되는 문서입니다.</span> HTML 폼은 사용자와 상호작용할 수 있는 매우 강력한 도구입니다. 그러나 역사적으로 나 기술적인 이유로 사용자에게 항상 명확하게 기능을 제공할 수 있는 것은 아닙니다. 이 가이드에서 HTML 폼 관점에서 스타일 구조, 사용자 위젯으로 데이터 다루기 등 모든 것을 다룰 것입니다. 이러한 강력한 기술들을 즐기길 바랍니다!</p> + +<h2 id="항목" style="line-height: 30px; font-size: 2.14285714285714rem;">항목</h2> + +<ol> + <li><a href="https://developer.mozilla.org/ko/docs/Web/Guide/HTML/%ED%8F%BC/My_first_HTML_form">나의 첫 HTML 폼</a></li> + <li><a href="/en-US/docs/HTML/Forms/How_to_structure_an_HTML_form" title="/en-US/docs/HTML/Forms/How_to_structure_an_HTML_form">HTML HTML 폼 구성 방법</a></li> + <li><a href="/en-US/docs/HTML/Forms/The_native_form_widgets" title="/en-US/docs/HTML/Forms/The_native_form_widgets">기본 폼 위젯</a></li> + <li>CSS와 HTML 폼 + <ol> + <li><a href="/en-US/docs/HTML/Forms/Styling_HTML_forms" title="/en-US/docs/HTML/Forms/Styling_HTML_forms">HTML 폼 스타일</a></li> + <li><a href="/en-US/docs/Web/Guide/HTML/Forms/Advanced_styling_for_HTML_forms" title="/en-US/docs/Advanced_styling_for_HTML_forms">HTML 폼을 위한 고급 스타일</a></li> + <li><a href="/en-US/docs/Property_compatibility_table_for_form_widgets" title="/en-US/docs/Property_compatibility_table_for_form_widgets">폼 위젯을 위한 호환성 테이블 속성</a></li> + </ol> + </li> + <li><a href="/en-US/docs/HTML/Forms/Sending_and_retrieving_form_data" title="/en-US/docs/HTML/Forms/Sending_and_retrieving_form_data">데이터 주고 받기</a></li> + <li><a href="/en-US/docs/HTML/Forms/Data_form_validation" title="/en-US/docs/HTML/Forms/Data_form_validation">데이터 유효성 검사</a></li> + <li><a href="/en-US/docs/HTML/Forms/How_to_build_custom_form_widgets" title="/en-US/docs/HTML/Forms/How_to_build_custom_form_widgets">사용자 폼 위젯 만드는 방법</a></li> + <li><a href="/en-US/docs/HTML/Forms/Sending_forms_through_JavaScript" title="/en-US/docs/HTML/Forms/Sending_forms_through_JavaScript">자바스크립트를 통해서 폼 전달 하기</a> + <ol> + <li><a href="/en-US/docs/DOM/XMLHttpRequest/FormData/Using_FormData_Objects" title="/en-US/docs/DOM/XMLHttpRequest/FormData/Using_FormData_Objects">FormData 객체 사용</a></li> + </ol> + </li> + <li><a href="/en-US/docs/HTML/Forms/HTML_forms_in_legacy_browsers" title="/en-US/docs/HTML/Forms/HTML_forms_in_legacy_browsers">기존 브라우저에서 HTML 폼</a></li> +</ol> + +<h2 id="HTML_문서" style="line-height: 30px; font-size: 2.14285714285714rem;">HTML 문서</h2> + +<h3 id="HTML_요소" style="line-height: 24px; font-size: 1.71428571428571rem;">HTML 요소</h3> + +<table> + <thead> + <tr> + <th scope="col">요소</th> + <th scope="col">관련 DOM 인터페이스</th> + <th scope="col">설명</th> + </tr> + </thead> + <tbody> + <tr> + <td style="vertical-align: top;">{{HTMLElement("button")}}</td> + <td style="vertical-align: top;">{{domxref("HTMLButtonElement")}}</td> + <td style="vertical-align: top;"><code>button 요소는 클릭할 수 있는 버튼을 나타낸다.</code></td> + </tr> + <tr> + <td style="vertical-align: top;">{{HTMLElement("datalist")}}</td> + <td style="vertical-align: top;">{{domxref("HTMLDataListElement")}}</td> + <td style="vertical-align: top;"><span style="font-family: 'Courier New';">datalist</span> 요소는 다른 폼 요소의 값에 대한 가능한 옵션들을 나타내는 {{ HTMLElement("option") }} 요소의 집합을 포함합니다. </td> + </tr> + <tr> + <td style="vertical-align: top;">{{HTMLElement("fieldset")}}</td> + <td style="vertical-align: top;">{{domxref("HTMLFieldSetElement")}}</td> + <td style="vertical-align: top;"><span style="font-family: 'Courier New';">fieldset 요소는</span> 폼 안에 여러 폼 요소들을 그룹화 하는데 사용됩니다.</td> + </tr> + <tr> + <td style="vertical-align: top;">{{HTMLElement("form")}}</td> + <td style="vertical-align: top;">{{domxref("HTMLFormElement")}}</td> + <td style="vertical-align: top;"><code>form</code> 요소는 사용자가 정보를 웹서버로 전송하도록 상호작용하는 요소를 포함하는 문서의 부분으로 나타냅니다.</td> + </tr> + <tr> + <td style="vertical-align: top;">{{HTMLElement("input")}}</td> + <td style="vertical-align: top;">{{domxref("HTMLInputElement")}}</td> + <td style="vertical-align: top;"><code>input 요소는</code> 대화형 컨트롤 폼들을 생성하는데 사용됩니다.</td> + </tr> + <tr> + <td style="vertical-align: top;">{{HTMLElement("keygen")}}</td> + <td style="vertical-align: top;">{{domxref("HTMLKeygenElement")}}</td> + <td style="vertical-align: top;"><code>keygen</code> 요소는 HTML 폼 요소의 일부로서 쉽게 키 데이터를 발생시키고 공개키를 전송을 위해서 존재 합니다.</td> + </tr> + <tr> + <td style="vertical-align: top;">{{HTMLElement("label")}}</td> + <td style="vertical-align: top;">{{domxref("HTMLLabelElement")}}</td> + <td style="vertical-align: top;"><code>label</code> 요소는 사용자 인터페이스 항목에 대한 캡션을 나타냅니다.</td> + </tr> + <tr> + <td style="vertical-align: top;">{{HTMLElement("legend")}}</td> + <td style="vertical-align: top;">{{domxref("HTMLLegendElement")}}</td> + <td style="vertical-align: top;"><code>legend</code> 요소는 상위 요소인 {{ HTMLElement("fieldset") }} 컨텐츠를 위한 캡션을 나타냅니다.</td> + </tr> + <tr> + <td style="vertical-align: top;">{{HTMLElement("meter")}}</td> + <td style="vertical-align: top;">{{domxref("HTMLMeterElement")}}</td> + <td style="vertical-align: top;"><code>meter </code>요소는 알려진 범위 안에 정해 저 있는 스칼라 값이나 소수 값 주 하나를 나타냅니다.</td> + </tr> + <tr> + <td style="vertical-align: top;">{{HTMLElement("optgroup")}}</td> + <td style="vertical-align: top;">{{domxref("HTMLOptGroupElement")}}</td> + <td style="vertical-align: top;"><code>optgroup</code> 요소는 {{ HTMLElement("select") }} 요소 안에 있는 옵션 그룹을 생성합니다.</td> + </tr> + <tr> + <td style="vertical-align: top;">{{HTMLElement("option")}}</td> + <td style="vertical-align: top;">{{domxref("HTMLOptionElement")}}</td> + <td style="vertical-align: top;">HTML<em> </em><code>option<em> </em></code>요소는 {{ HTMLElement("select") }}, {{ HTMLElement("optgroup") }} 또는 {{ HTMLElement("datalist") }}요소 안에 항목을 나타내는 컨트롤을 생성하는데 사용됩니다.</td> + </tr> + <tr> + <td style="vertical-align: top;">{{HTMLElement("output")}}</td> + <td style="vertical-align: top;">{{domxref("HTMLOutputElement")}}</td> + <td style="vertical-align: top;"><code>output </code>요소는 계산 결과를 나타냅니다.</td> + </tr> + <tr> + <td style="vertical-align: top;">{{HTMLElement("progress")}}</td> + <td style="vertical-align: top;">{{domxref("HTMLProgressElement")}}</td> + <td style="vertical-align: top;"><code>progress</code> 요소는 작업 완료 진행 상태를 나타내는데 사용됩니다.</td> + </tr> + <tr> + <td style="vertical-align: top;">{{HTMLElement("select")}}</td> + <td style="vertical-align: top;">{{domxref("HTMLSelectElement")}}</td> + <td style="vertical-align: top;"><code>select</code> 요소는 옵션 메뉴를 제공하는 컨트롤을 나타냅니다.</td> + </tr> + <tr> + <td style="vertical-align: top;">{{HTMLElement("textarea")}}</td> + <td style="vertical-align: top;">{{domxref("HTMLTextAreaElement")}}</td> + <td style="vertical-align: top;"><code>textarea</code> 요소는 다중 라인 일반 텍스트 편집 컨트롤을 나타냅니다.</td> + </tr> + </tbody> +</table> + +<div class="note"> +<p><strong>Note:</strong> 모든 폼 요소들이나 모든 HTML요소들은 {{domxref("HTMLElement")}} 돔 인터페이스를 지원합니다.</p> +</div> + +<h3 id="HTML_속성" style="line-height: 24px; font-size: 1.71428571428571rem;">HTML 속성</h3> + +<table class="standard-table"> + <thead> + <tr> + <th>속성 이름</th> + <th>요소</th> + <th>설명</th> + </tr> + </thead> + <tbody> + <tr> + <td>accept</td> + <td>{{ HTMLElement("form") }}, {{ HTMLElement("input") }}</td> + <td>서버가 받는 형식 목록, 일반적으로 file 형식을 사용합니다.</td> + </tr> + <tr> + <td style="white-space: nowrap;">accept-charset</td> + <td>{{ HTMLElement("form") }}</td> + <td>지원하는 문자 집합 목록</td> + </tr> + <tr> + <td>action</td> + <td>{{ HTMLElement("form") }}</td> + <td>폼을 통해서 전송 정보를 처리하는 프로그램의 URL </td> + </tr> + <tr> + <td>autocomplete</td> + <td>{{ HTMLElement("form") }}, {{ HTMLElement("input") }}</td> + <td>폼 안에서 브라우저로 부터 자동으로 완성되는 기본 값을 가진 컨트롤 인지 아닌지 나타냅니다.</td> + </tr> + <tr> + <td>autofocus</td> + <td>{{ HTMLElement("button") }}, {{ HTMLElement("input") }}, {{ HTMLElement("keygen") }}, {{ HTMLElement("select") }}, {{ HTMLElement("textarea") }}</td> + <td>페이지가 로드된 후 요소가 자동으로 포커스 해야 되는지 설정합니다.</td> + </tr> + </tbody> + <tbody> + <tr> + <td>challenge</td> + <td>{{ HTMLElement("keygen") }}</td> + <td>공개 키(public key)와 함께 전송되는 문자열입니다.</td> + </tr> + <tr> + <td>checked</td> + <td>{{ HTMLElement("input") }}</td> + <td> + <p>해당 요소가 페이지가 로드될 때 체크된 상태로 나타나도록 설정합니다. </p> + </td> + </tr> + <tr> + <td>cols</td> + <td>{{ HTMLElement("textarea") }}</td> + <td> + <p>textarea의 세로줄 수를 설정합니다.</p> + </td> + </tr> + <tr> + <td>data</td> + <td>{{ HTMLElement("object") }}</td> + <td>자원의 URL을 명시합니다.</td> + </tr> + <tr> + <td>dirname</td> + <td>{{ HTMLElement("input") }}, {{ HTMLElement("textarea") }}</td> + <td></td> + </tr> + <tr> + <td>disabled</td> + <td>{{ HTMLElement("button") }}, {{ HTMLElement("fieldset") }}, {{ HTMLElement("input") }}, {{ HTMLElement("keygen") }}, {{ HTMLElement("optgroup") }}, {{ HTMLElement("option") }}, {{ HTMLElement("select") }}, {{ HTMLElement("textarea") }}</td> + <td>사용자가 요소와 상호 작용할 수 있는 지 나타냅니다.</td> + </tr> + <tr> + <td>enctype</td> + <td>{{ HTMLElement("form") }}</td> + <td>POST방식으로 전송되는 데이터의 타입을 설정합니다.</td> + </tr> + <tr> + <td>for</td> + <td>{{ HTMLElement("label") }}, {{ HTMLElement("output") }}</td> + <td>Describes elements which belongs to this one.</td> + </tr> + <tr> + <td>form</td> + <td>{{ HTMLElement("button") }}, {{ HTMLElement("fieldset") }}, {{ HTMLElement("input") }}, {{ HTMLElement("keygen") }}, {{ HTMLElement("label") }}, {{ HTMLElement("meter") }}, {{ HTMLElement("object") }}, {{ HTMLElement("output") }}, {{ HTMLElement("progress") }}, {{ HTMLElement("select") }}, {{ HTMLElement("textarea") }}</td> + <td> + <p>요소의 소유자인 폼을 나타냅니다.</p> + </td> + </tr> + </tbody> + <tbody> + <tr> + <td>high</td> + <td>{{ HTMLElement("meter") }}</td> + <td>Indicates the lower bound of the upper range.</td> + </tr> + <tr> + <td>keytype</td> + <td>{{ HTMLElement("keygen") }}</td> + <td>Specifies the type of key generated.</td> + </tr> + <tr> + <td>list</td> + <td>{{ HTMLElement("input") }}</td> + <td>Identifies a list of pre-defined options to suggest to the user.</td> + </tr> + <tr> + <td>low</td> + <td>{{ HTMLElement("meter") }}</td> + <td>Indicates the upper bound of the lower range.</td> + </tr> + <tr> + <td>max</td> + <td>{{ HTMLElement("input") }}, {{ HTMLElement("meter") }}, {{ HTMLElement("progress") }}</td> + <td>허용되는 최댓값을 나타냅니다.</td> + </tr> + <tr> + <td>maxlength</td> + <td>{{ HTMLElement("input") }}, {{ HTMLElement("textarea") }}</td> + <td>요소에서 허용되는 특징의 최대 수를 명시합니다.</td> + </tr> + <tr> + <td>method</td> + <td>{{ HTMLElement("form") }}</td> + <td>Defines which HTTP method to use when submitting the form. Can be GET (default) or POST.</td> + </tr> + <tr> + <td>min</td> + <td>{{ HTMLElement("input") }}, {{ HTMLElement("meter") }}</td> + <td>허용되는 최솟값을 나타냅니다.</td> + </tr> + <tr> + <td>multiple</td> + <td>{{ HTMLElement("input") }}, {{ HTMLElement("select") }}</td> + <td>Indicates whether multiple values can be entered in an input of the type <code>email</code> or <code>file</code>.</td> + </tr> + <tr> + <td>name</td> + <td>{{ HTMLElement("button") }}, {{ HTMLElement("form") }}, {{ HTMLElement("fieldset") }}, {{ HTMLElement("input") }}, {{ HTMLElement("keygen") }}, {{ HTMLElement("output") }}, {{ HTMLElement("select") }}, {{ HTMLElement("textarea") }}</td> + <td> + <p>요소의 이름. For example used by the server to identify the fields in form submits.</p> + </td> + </tr> + <tr> + <td>novalidate</td> + <td>{{ HTMLElement("form") }}</td> + <td>This attribute indicates that the form shouldn't be validated when submitted.</td> + </tr> + <tr> + <td>optimum</td> + <td>{{ HTMLElement("meter") }}</td> + <td>Indicates the optimal numeric value.</td> + </tr> + <tr> + <td>pattern</td> + <td>{{ HTMLElement("input") }}</td> + <td>Defines a regular expression which the element's value will be validated against.</td> + </tr> + <tr> + <td>placeholder</td> + <td>{{ HTMLElement("input") }}, {{ HTMLElement("textarea") }}</td> + <td>Provides a hint to the user of what can be entered in the field.</td> + </tr> + <tr> + <td>readonly</td> + <td>{{ HTMLElement("input") }}, {{ HTMLElement("textarea") }}</td> + <td>Indicates whether the element can be edited.</td> + </tr> + <tr> + <td>required</td> + <td>{{ HTMLElement("input") }}, {{ HTMLElement("select") }}, {{ HTMLElement("textarea") }}</td> + <td>Indicates whether this element is required to fill out or not.</td> + </tr> + <tr> + <td>rows</td> + <td>{{ HTMLElement("textarea") }}</td> + <td>Defines the number of rows in a textarea.</td> + </tr> + <tr> + <td>selected</td> + <td>{{ HTMLElement("option") }}</td> + <td>Defines a value which will be selected on page load.</td> + </tr> + <tr> + <td>size</td> + <td>{{ HTMLElement("input") }}, {{ HTMLElement("select") }}</td> + <td>Defines the width of the element (in pixels). If the element's <code>type</code> attribute is <code>text</code> or <code>password</code> then it's the number of characters.</td> + </tr> + <tr> + <td>src</td> + <td>{{ HTMLElement("input") }}</td> + <td>The URL of the embeddable content.</td> + </tr> + <tr> + <td>step</td> + <td>{{ HTMLElement("input") }}</td> + <td></td> + </tr> + <tr> + <td>target</td> + <td>{{ HTMLElement("form") }}</td> + <td></td> + </tr> + <tr> + <td>type</td> + <td>{{ HTMLElement("button") }}, {{ HTMLElement("input") }}</td> + <td>Defines the type of the element.</td> + </tr> + <tr> + <td>usemap</td> + <td>{{ HTMLElement("input") }}</td> + <td></td> + </tr> + <tr> + <td>value</td> + <td>{{ HTMLElement("button") }}, {{ HTMLElement("option") }}, {{ HTMLElement("input") }}, {{ HTMLElement("meter") }}, {{ HTMLElement("progress") }}</td> + <td>Defines a default value which will be displayed in the element on page load.</td> + </tr> + <tr> + <td>wrap</td> + <td>{{ HTMLElement("textarea") }}</td> + <td>Indicates whether the text should be wrapped.</td> + </tr> + </tbody> +</table> + +<h3 id="Normative_reference" style="line-height: 24px; font-size: 1.71428571428571rem;">Normative reference</h3> + +<ul> + <li><a href="http://www.w3.org/TR/html5/forms.html" lang="en" rel="external" title="http://www.w3.org/TR/html5/forms.html">W3C HTML5 Specification (Forms)</a></li> + <li><a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html#forms" rel="external" title="http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html#forms">WHATWG HTML Living Standard (Forms)</a></li> +</ul> diff --git a/files/ko/learn/html/forms/sending_and_retrieving_form_data/index.html b/files/ko/learn/html/forms/sending_and_retrieving_form_data/index.html new file mode 100644 index 0000000000..f1d7c35437 --- /dev/null +++ b/files/ko/learn/html/forms/sending_and_retrieving_form_data/index.html @@ -0,0 +1,249 @@ +--- +title: Sending and retrieving form data +slug: Learn/HTML/Forms/Sending_and_retrieving_form_data +translation_of: Learn/Forms/Sending_and_retrieving_form_data +--- +<p><span style="line-height: 1.5;">많은 경우 HTML 폼은 서버에 데이터를 전송할 목적으로 사용된다. </span>서버는 데이터를 처리하고 사용자에게 응답을 보낼 것이다. 간단한 것 처럼 보이지만 데이터가 서버나 사용자에게 피해를 입히지 않기 위해서는 몇가지를 명심해야한다.</p> + +<h2 id="데이터는_어디로_갈까">데이터는 어디로 갈까?</h2> + +<h3 id="클라이언트서버_구조">클라이언트/서버 구조</h3> + +<p><span style="line-height: 1.5;">웹은 간단히 말하면 클라이언트(파이어폭스, 크롬, 사파리, IE 등)는 서버(아파치, Nginx, IIS, 톰켓 등)로 HTTP프로토콜을 사용해 요청을 하는 클라이언트/서버 구조를 기본으로 작동된다.</span> 서버 응답은 요청과 똑같은 프로토콜을 사용한다.</p> + +<p><img alt="A basic schema of the Web client/server architecture" src="/files/4291/client-server.png" style="height: 141px; width: 400px;"></p> + +<p>클라이언트 측에서 HTML폼 만큼 사용친화적으로 HTTP 요청을 서버에 보내는 편리한 것이 없다.이것은 사용자가 정보를 HTTP요청으로 전달을 할 수있게 만든다.</p> + +<h3 id="클라이언트측_데이터_보내기">클라이언트측: 데이터 보내기</h3> + +<p>{{HTMLElement("form")}} 요소는 데이터 전송 방법을 정의한다. 제공하는 모든 속성은 사용자가 submit 버튼을 누를때 보내질 요청을 구성할 수 있도록 설계되었다. 두가지 중요한 속성은 {{htmlattrxref("action","form")}} 와 {{htmlattrxref("method","form")}}이다.</p> + +<h4 id="htmlattrxrefactionform_속성">{{htmlattrxref("action","form")}} 속성</h4> + +<p>이 속성은 데이터를 어디로 보낼 것인지 지정한다. 이 값은 반드시 유효한 URL이어야 한다.만약 이 속성을 지정하지 않으면 데이터는 폼이 있는 페이지의 URL로 보내질 것이다.</p> + +<h5 id="Examples">Examples</h5> + +<p>첫번째 예제로 데이터는 http://foo.com로 보낼 것이다.</p> + +<pre class="brush: html"><form action="http://foo.com"></pre> + +<p class="brush: html">여기에서 데이터는 폼 페이지를 호스팅을 하는 같은 서버로 전송 되지만, 서버의 다른 URL로 전송된다.</p> + +<pre class="brush: html"><form action="/somewhere_else"></pre> + +<p class="brush: html">아래와 같이 속성을 지정하지 않으면 {{HTMLElement("form")}} 속성은 데이터를 폼을 포함한 페이지 주소로 보낼 것이다.</p> + +<pre class="brush: html"><form></pre> + +<p class="brush: html">이전에 많은 페이지들은 데이터를 반드시 폼을 포함하는 페이지와 같은 페이지에 보내는 것을 나타내는 표기법을 다음과 같이 사용했다. 그러나 HTML5 이후로 속성은 필수로 지정하지 않아도 되기 떄문에 이제 더이상 필요하지 않는다.</p> + +<pre class="brush: html"><form action="#"></pre> + +<div class="note"> +<p><strong>Note: </strong>HTTPS(보안 HTTP) 프로토콜을 사용하는 URL을 지정하는 것도 가능하다. 이 것을 사용하면 폼 자체가 안전하지 않은 페이지에 HTTP를 이용해서 접근하는 곳에 호스트된 경우에 데이터는 나머지 요청들과 함께 암호화된다. <span style="line-height: 1.5;">반면, 만약 폼이 보안 페이지에서 호스트 된 경우라도 </span> {{htmlattrxref("action","form")}} 속성에서 <span style="line-height: 1.5;">안전하지 않은 HTTP URL을 지정하면 모든 브라우저는 데이터가 암호화되지 않았기 때문에 데이터를 보낼때마다 보안 경고를 출력할 것이다 </span></p> +</div> + +<h4 id="htmlattrxrefmethodform_속성">{{htmlattrxref("method","form")}} 속성</h4> + +<p>이 속성은 데이터를 어떻게 보낼 것인지 정의한다. <a href="/en-US/docs/HTTP" title="/en-US/docs/HTTP">HTTP protocol</a> <span style="line-height: 1.5;">은 요청 방법에 대해 다양한 방법들을 제공한다. HTML 폼 데이터는 오직 2가지 방법으로 만 전송 할 수 있는데 바로 GET 방식과 POST방식이 있다.</span></p> + +<p>이 두 가지 방식의 차이점을 이해하기 위해서는 뒤로 가서 HTTP가 어떻게 작동하는지 살펴봐야한다. 웹에서 리소스에 접근 할 때마다, 브라우저는 URL에 요청을 보낸다. HTTP요청은 두 가지 부분으로 나누어진다. 브라우저 수용력에 대한 전역 메타 테이터들을 포함하는 헤더와 서버에서 지정된 요청을 처리하는데 필요한 정보를 포함하는 바디가 있다.</p> + +<h5 id="GET_방식">GET 방식</h5> + +<p><span style="line-height: 1.5;">GET 방식은 브라우저에서 서버에 주어진 리소스를 전달해달라고 말하기 위해 사용되는 방식이다. " 이봐 서버 난 이 리소스를 원해" 이 경우 브라우저는 바디가 비어 있는 요청을 하게 된다. </span>바디가 비어 있기 때문에, 만약 폼이 이 방식를 통하여 전송 하는 경우 데이터는 URL에 포함되어 서버로 보내진다.</p> + +<h6 id="예제">예제</h6> + +<p>다음 폼을 생각 해 봅시다.</p> + +<pre class="brush: html"><form action="http://foo.com" method="get"> + <input name="say" value="Hi"> + <input name="to" value="Mom"> + <button>Send my greetings</button> +</form></pre> + +<p>GET 방식을 사용하면 HTTP 요청은 다음과 같다.</p> + +<pre>GET /?say=Hi&to=Mom HTTP/1.1 +Host: foo.com</pre> + +<h5 id="POST_방식">POST 방식</h5> + +<p><span style="line-height: 1.5;">POST 방식은 조금 다르다. </span>이는 브라우저의 HTTP요청 바디안에 제공되는 데이터를 고려한 응답을 요구하기 위해 서버로 보내는 방식이다. "이봐 서버 이 데이터를 보고 이거에 맞는 데이터를 보내봐" <span style="line-height: 1.5;">만약 폼이 이 방식으로 사용하여 요청을 한다면 데이터는 HTTP요청 바디에 추가되어 전송된다.</span></p> + +<p>예제</p> + +<p>이 폼을 생각해보라(위 예제와 똑같다)</p> + +<pre class="brush: html"><form action="http://foo.com" method="post"> + <input name="say" value="Hi"> + <input name="to" value="Mom"> + <button>Send my greetings</button> +</form></pre> + +<p>POST 방식을 사용하면 다음과 같이 HTTP 요청을 할 것이다,</p> + +<pre>POST / HTTP/1.1 +Host: foo.com +Content-Type: application/x-www-form-urlencoded +Content-Length: 13 + +say=Hi&to=Mom</pre> + +<p>Content-Length 헤더는 바디의 크기를 나태내고, Content-Type 헤더는 서버에 보낼 리소스의 종류 나태낸다. 우리는 비트(bit/조금씩?)에서 이러한 헤더를 설명 할 것이다.</p> + +<p><span style="line-height: 1.5;">물론 http 요청은 절대 사용자에게 표시되지 않는다(파이어폭스 웹 콘솔이나 크롬 개발자 툴을 이용하지 않는이상). </span>사용자에게 보여지는 것은 호출한 URL뿐이다. <span style="line-height: 1.5;">그래서 GET 요청은 사용자에게 URL바에서 데이터를 볼 수있지만, POST 요청은 그러지 못한다. 이것은 두가지 이유에서 매우 중요하다.</span></p> + +<ol> + <li>만약 패스워드를 전송해야 되는 경우(또는 민간한 데이터의 부분), 절대 URL 바에 데이터를 출력하는 GET 방식을 사용해서는 안된다.</li> + <li>만약 거대한 데이터를 보내는경우 POST 방식이 선호 된다. 왜냐하면 몇몇 브라우저는 URL들의 크기를 제한하기 떄문이다. 또한 많은 서버들이 URL들의 길이를 제한한다.</li> +</ol> + +<h3 id="서버측_데이터_가져오기">서버측: 데이터 가져오기</h3> + +<p>어떠한 HTTP 방식을 선택 하든지 서버는 키/ 벨류 쌍의 목록과 같은 데이터를 얻기 위해 파싱된 문자열을 받을 것이다. 이러한 목록에 접근하는 방법은 사용하는 개발 플랫폼에 의존되고 어떠한 지정된 프레임워크에서 이것을 사용 할 수 있을것이다. 또한 사용 하는 기술은 동일한 키를 어떻게 처리할 것인지 결정한다. 보통 가장 마지막에 수신된 값이 우선순위를 가진다.</p> + +<h4 id="예제_PHP_날것">예제: PHP 날것</h4> + +<p>PHP 데이타에 접근 하기 위하여 몇가지 글로벌 객체를 제공한다. POST 방식 사용했다고 생각해보면, 다음과 같은 예제는 단순히 데이터만 받아 사용자에게 출력만 한다. 물론 데이터로 무엇을 할 것인지는 너어게 달려있다. 아마도 데이터를 사용자에게 출력하거나, 데이터베이스에 저장, 이메일에 전송 또는 다른 방법으로 처리할 것이다.</p> + +<pre class="brush: php"><?php + // The global $_POST variable allow to access the data send with the POST method + // To access the data send with the GET method, you can use $_GET + $say = htmlspecialchars($_POST['say']); + $to = htmlspecialchars($_POST['to']); + + echo $say, ' ', $to;</pre> + +<p>이 예제는 우리가 보낸 데이터를 페이지에 출력 할 것이다. 이 예제는 다음과 같이 출력할 것이다.</p> + +<pre>Hi Mom</pre> + +<h4 id="예제_Python">예제: Python</h4> + +<p>이 예제는 파이썬을 사용하여 제공된 데이터를 웹페이지에 출력하는 예제입니다. <span style="line-height: 1.5;">CGI 파이썬 패키지를 이용하여 폼데이터에 접근한다.</span></p> + +<pre class="brush: python">#!/usr/bin/env python +import html +import cgi +import cgitb; cgitb.enable() # for troubleshooting + +print("Content-Type: text/html") # HTTP header to say HTML is following +print() # blank line, end of headers + +form = cgi.FieldStorage() +say = html.escape(form["say"].value); +to = html.escape(form["to"].value); + +print(say, " ", to)</pre> + +<p>이 결과는 PHP와 똑같다?.</p> + +<pre>Hi Mom</pre> + +<h4 id="다른_언어와_프레임_워크">다른 언어와 프레임 워크</h4> + +<p> <a href="/en-US/docs/" title="/en-US/docs/">Perl</a>, <a href="/en-US/docs/" title="/en-US/docs/">Java</a>, <a href="http://www.microsoft.com/net" title="http://www.microsoft.com/net">.Net</a>, <a href="/en-US/docs/" title="/en-US/docs/">Ruby</a>등 이와 같은 다른 서버측 기술이 있다. 이중에 최고라고 생각되는 것을 사용하면된다. 즉, 까다로운 일이 될 수 있기 때문에, 직접 기술을 사용하는 것은 매우 드문 일이 있음을 언급하는 것은 가치가있다.(?) <span style="line-height: 1.5;">다음과 같은 폼을 더 쉽게 다루기위해 다음과 같은 좋은 프레임 워크들이 사용된다.</span></p> + +<ul> + <li><a href="http://symfony.com/" rel="external" title="http://symfony.com/">Symfony</a> for PHP</li> + <li><a href="https://www.djangoproject.com/" rel="external" title="https://www.djangoproject.com/">Django</a> for Python</li> + <li><a href="http://rubyonrails.org/" rel="external" title="http://rubyonrails.org/">Ruby On Rails</a> for Ruby</li> + <li><a href="http://grails.org/" rel="external" title="http://grails.org/">Grails</a> for Java</li> + <li>etc.</li> +</ul> + +<p><span style="line-height: 1.5;">이러한 프레임 워크를 사용하는 경우에도 폼을 다루는 것은 어쩔수 없이 쉽지 않다는 것을 주목을 할 필요가 있다.</span> 그러나 이것을 사용하면 많은 시간을 절약 할 수 있다.</p> + +<h2 id="특별한_경우_파일_보내기">특별한 경우: 파일 보내기</h2> + +<p>파일은 HTML 폼에서 특별한 경우이다. 파일은 2진 데이터 또는 다른 데이터는 텍스트 데이터로 간주된다.HTTP는 텍스트 프로토콜 이기 때문에 2진 데이터를 다루기 위해서는 특별한 요구 사항이있다.</p> + +<h3 id="htmlattrxrefenctypeform_속성">{{htmlattrxref("enctype","form")}} 속성</h3> + +<p><span style="line-height: 1.5;">이 속성은 Content-Type HTTP 헤더의 값을 지정할 수 있게 해준다. </span>서버에 데이터가 무슨 종류인지 전달하기 떄문에 이 해더는 매우 중요하다. <span style="line-height: 1.5;">기본 값으로는 application/x-www-form-urlencoded. 이다. 사람 말로는 "이 폼 데이터는 URL 폼 형태로 인코딩되어 있습니다" 이다</span></p> + +<p>만약 파일을 보내고 싶다면 두 가지를 해야한다.</p> + +<ul> + <li>{{htmlattrxref("method","form")}} 속성을 POST 속성으로 지정 해야한다. 왜냐하면 파일 콘텐츠는 폼을 이용하여 URL 매개변수로 보낼수 없기 때문이다.</li> + <li>{{htmlattrxref("enctype","form")}}의 값을 multipart/form-data 이라고 지정 해야한다. 왜냐하면 데이터는 여러 조각으로 나누워 지고 각 파일 조각에 같이 보내질 폼바디 텍스트가 추가 되기 때문이다.</li> +</ul> + +<p>예제 </p> + +<pre class="brush: html"><form method="post" enctype="multipart/form-data"> + <input type="file" name="myFile"> + <button>Send the file</button> +</form></pre> + +<div class="note"> +<p><strong>Note:</strong> 몇 브라우저는 {{htmlattrxref("multiple","input")}}속성을 {{HTMLElement("input")}}요소에 지원하여 한번에 여러 요소를 전달 할 수 있다. 이러한 파일을 서버측에서 다루는 방법은 서버에서 어떠한 기술을 사용하냐에 따라서 매우 달라진다. 앞에서 언급 한바와 같이 프레임워크를 사용하면 더 쉽게 이용할 수있다.</p> +</div> + +<div class="warning"> +<p><strong>Warning:</strong> 많은 서버들이 남용을 예방하기 위해 HTTP요청과 파일의 크기를 제한하도록 구성된다. 파일을 전송하기 전에 서버 관리자에게 제한 크기를 확인하는것이 중요하다.</p> +</div> + +<h2 id="보안_코너">보안 코너</h2> + +<p>데이터를 서버로 보낼 떄마다 보안성에 대하여 생각해 봐야한다. HTML폼은 서버를 공격하는데 첫번째 매개변수가 될 수있다. 문제는 HTML폼에서 오지 않는다. 서버에서 어떻게 처리하냐에 따라 문제가 발생한다.</p> + +<h3 id="일반적인_보안_결함">일반적인 보안 결함</h3> + +<p>무엇을 하는지에 따라 잘 알려진 보안 문제가 있다.</p> + +<h4 id="XSS_과_CSRF">XSS 과 CSRF</h4> + +<p>크로스 사이트 스크립팅(XSS)과 크로스 사이트 요청 위조(CSRF)은 데이터를 출력하기 위해 사용자나 다른 사용자에게 데이터를 보낼떄 공격하는 일반적인 유형이다.</p> + +<p>XSS 공격자는 다른 사용자가 볼 웹 페이지에 클라이언트 측 스크립트를 주입할 수있다.크로스 사이트 스크립팅 취약점은 공격자가 동일 출처 정책(<a href="/en-US/docs/JavaScript/Same_origin_policy_for_JavaScript" style="line-height: 1.5;" title="/en-US/docs/JavaScript/Same_origin_policy_for_JavaScript">same origin policy</a><span style="line-height: 1.5;">)의 접근 제어를 우회하여 사용 될 수 있다.</span><span style="line-height: 1.5;"> </span><span style="line-height: 1.5;">이러한 공격은 조금 불편함에서 심각한 보안 위험에 이르기 까지 다양하게 영향을 미친다.</span></p> + +<p>CSRF는 XSS와 비슷하게 공격자가 같은 방법으로 시작한다. —클라이언트 스크립트를 웹페이지에 주입한다. - 그러나 이것의 대상은 다르다. CSRF 공격자는 높은 권한 계정(서버 관리자 같은)으로 권한을 상승하려고 시도하고 하지 말아야할 행동들을 할것이다.(예를들어 신뢰 할 수없는 사용자에게 데이터 전송하는 것)</p> + +<p>XSS 공격자는 사용자가 웹사이트에 대하여 가진 신뢰를 이용하여 공격자는 웹사이트가 사용자를 신뢰한다는 것을 이용한다.</p> + +<p>이러한 공격을 방지하려면 사용자가 서버에 보내는 데이터를 항상 확인해야하며 해당 내용을 표시해야 하는 경우 사용자가 제공한 HTML 콘텐츠를 표시하지 말아야 한다. 대신, 당신이 보여주려는 데이터가 사용자가 제공한 것과 동일한 데이터가 아니도록 데이터를 처리해야 한다. 현재 시장에 나와있는 거의 모든 프레임 워크는 어떤 유저가 보내는 데이터라도 HTML{{HTMLElement ( "script")}},{{HTMLElement ( "iframe")}} 및 {{HTMLElement ( "object")}} 요소를 데이터에서 제거하는 최소한의 필터를 구현한다. 이는 위험을 완화하는 데 도움은 되지만 반드시 근절한다고 보장할 수는 없다.</p> + +<h4 id="SQL_injection">SQL injection</h4> + +<p>SQL injection is a type of attack that tries to perform actions on a database used by the target web site. This typically involves sending an SQL request and hopes that the server will execute it (many times when the application server tries to store the data). This is actually <a href="https://www.owasp.org/index.php/Category:OWASP_Top_Ten_Project" rel="external" title="https://www.owasp.org/index.php/Category:OWASP_Top_Ten_Project">one of the main vector attacks against web sites</a>.</p> + +<p>The consequences can be terrible, ranging from data loss to access to a whole infrastructure by using privilege escalation. This is a very serious threat and you should never store data sent by a user without performing some sanitization (for example, by using <code><a href="http://www.php.net/manual/en/function.mysql-real-escape-string.php" rel="external" title="http://www.php.net/manual/en/function.mysql-real-escape-string.php">mysql_real_escape_string()</a></code> on a PHP/MySQL infrastructure).</p> + +<h4 id="HTTP_header_injection_와_email_injection">HTTP header injection 와 email injection</h4> + +<p>These kinds of attacks can occur when your application builds HTTP headers or emails based on the data input by a user on a form. These won't directly damage your server or affect your users but are an open door to deeper problems such as session hijacking or phishing attacks.</p> + +<p>These attacks are mostly silent, and can turn your server into a <a href="http://en.wikipedia.org/wiki/Zombie_(computer_science)" rel="exernal" title="http://en.wikipedia.org/wiki/Zombie_(computer_science)">zombie</a>.</p> + +<h3 id="Be_paranoid_Never_trust_your_users">Be paranoid: Never trust your users</h3> + +<p>So, how do you fight these threats? This is a topic far beyond this guide; however there are a few rules it's good to keep in mind. The most important rule is: never ever trust your users, including yourself; even a trusted user could have been hijacked.</p> + +<p>All data that comes to your server must be checked and sanitized. Always. No exception.</p> + +<ul> + <li>Escape potentially dangerous characters. The specific characters you should be cautious with vary depending on the context in which the data is used and the server platform you employ, but all server-side languages have functions for this.</li> + <li>Limit the incoming amount of data to allow only what's necessary.</li> + <li>Sandbox uploaded files (store them on a different server and allow access to the file only through a different subdomain or even better through a fully different domain name).</li> +</ul> + +<p>If you follow these three rules of thumb, you should avoid many/most problems; however, it's always a good idea to get a security review performed by a competent third party. Don't assume that you've seen all the possible problems.</p> + +<h2 id="결론">결론</h2> + +<p>여기서 볼 수 있듯이 폼데이터는 쉽게 보낼수 있지만 어플리케이션에서 데이터를 확보하는것은 까다로운 일이 될 수 있다. 프론트 앤드 개발자가 기억해야 할 것은 데이터 모델만 보안을 정한다고 끝이 아니라는 것이다. Yes, as we'll see, it's possible to <a href="/en-US/docs/HTML/Forms/Data_form_validation" title="/en-US/docs/HTML/Forms/Data_form_validation">perform client side data validation</a> but the server can't trust this validation because it has no way to truly know what really happens on the client side.</p> + +<h2 id="볼거리">볼거리</h2> + +<p>If you want to learn more about securing a web application, you can dig into these resources:</p> + +<ul> + <li><a href="https://www.owasp.org/index.php/Main_Page" rel="external" title="https://www.owasp.org/index.php/Main_Page">The Open Web Application Security Project (OWASP)</a></li> + <li><a href="http://shiflett.org/" rel="external" title="http://shiflett.org/">Chris Shiflett's blog about PHP Security</a></li> + <li><a href="https://code.google.com/intl/en/edu/security/index.html" rel="external" title="https://code.google.com/intl/en/edu/security/index.html">Learning material from Google</a></li> +</ul> diff --git a/files/ko/learn/html/forms/your_first_html_form/index.html b/files/ko/learn/html/forms/your_first_html_form/index.html new file mode 100644 index 0000000000..b997fc1f08 --- /dev/null +++ b/files/ko/learn/html/forms/your_first_html_form/index.html @@ -0,0 +1,272 @@ +--- +title: 나의 첫 HTML 폼 +slug: Learn/HTML/Forms/Your_first_HTML_form +translation_of: Learn/Forms/Your_first_form +--- +<p>이 문서는 HTML 폼 소개 문서입니다. 간단한 폼들을 살펴보면서 HTML 폼을 만들기에 대한 기본적인 필요 사항들을 볼 수 있을 것이다. 이 문서는 HTML폼에 대해서는 아무것도 몰라도 되지만 다음 문서에 나와 있는 기본적인 HTML이나 CSS를 알아야 한다. (<a href="/en-US/docs/HTML/Introduction" title="/en-US/docs/HTML/Introduction">the basics of HTML</a>, <a href="/en-US/docs/CSS/Getting_Started" title="/en-US/docs/CSS/Getting_Started">CSS</a>)</p> + +<h2 id="시작하기전에" style="line-height: 30px;">시작하기전에</h2> + +<h3 id="HTML_폼_이란" style="line-height: 24px;">HTML 폼 이란?</h3> + +<p>HTML폼은 사용자와 웹사이트 또는 어플리케이션이 서로 상호 작용하는 것 중 중요한 기술 중에 하나이다. 폼은 사용자가 웹사이트에 데이터를 전송하는 것을 허용한다. 일반적으로 데이터는 웹 서버로 전송되지만 웹페이지가 데이터를 사용하기 위하여 사용할 수 도 있다.</p> + +<p>HTML 폼은 하나 이상의 위젯으로 만들어 진다. 이러한 위젯들은 텍스트 필드(한줄 또는 여러줄), 셀렉 박스, 버튼, 체크박스, 라디오 버튼이 될 수 있다. <span style="line-height: 1.5;">대부분 이러한 위젯들은 위젯을 설명하는 라벨과 함께 사용된다.</span></p> + +<h3 id="폼을_사용하려면_무엇이_필요합니까" style="line-height: 24px;">폼을 사용하려면 무엇이 필요합니까?</h3> + +<p>HTML을 다루기 위한 텍스트 에디터나 웹 브라우저외는 아무것도 필요 없습니다. <span style="line-height: 1.5;">물론 비주얼 스튜디오, 이클립트, 앱타나 등 통합개발환경(IDE)을 사용하면 많은 이점이 있지만 이것은 만드는 사람 마음이다.</span></p> + +<p>HTML 폼과 일반적인 HTML 요소의 주요 차이점은 폼에 의해 수집된 데이터는 대부분 웹서버에 전송된다는 점이다. 이런 경우 데이터를 받거나 처리하는 웹서버를 설정해야한다. 웹서버를 설정하는 방법은 이 문서의 범위를 벗어나지만 알고 싶다면 다음 문서를 참조 하시오 <a href="/en-US/docs/HTML/Forms/Sending_and_Retrieving_form_data" title="/en-US/docs/HTML/Forms/Sending_and_retrieving_form_data">Sending and retrieving form data</a>.</p> + +<h2 id="폼_디자인하기" style="line-height: 30px;">폼 디자인하기</h2> + +<p>코드를 보기전에 항상 잠시 뒤로 물러나 폼에 대하여 생각하는 것이 더 중요하다. 간단한 모형을 디자인 하는것은 개발자가 사용자에게 묻고 싶은 데이터를 올바르게 정의하는데 도움을 준다. 사용자 경험 (UX)의 관점에서 폼이 많을수록 사용자들이 더 줄어든다는 사실을 기억하는게 중요하다. 반드시 필요한것이 무엇인지 생각하면서 간단하게 유지하는 것이 중요하다. 폼 디자인은 사이트나 어플리케이션을 만드는 과정 중 중요한 단계이다. 폼들의 디자인은 이 문서의 범위를 벗어나지만 만약 더 자세하게 알고 싶은 경우 다음 문서를 참조 하세요.</p> + +<ul> + <li>Smashing는 폼 UX에 매우 좋은 잡지다 <a href="http://uxdesign.smashingmagazine.com/tag/forms/" rel="external" title="http://uxdesign.smashingmagazine.com/tag/forms/">good articles about forms UX</a>의 <a href="http://uxdesign.smashingmagazine.com/2011/11/08/extensive-guide-web-form-usability/" rel="external" title="http://uxdesign.smashingmagazine.com/2011/11/08/extensive-guide-web-form-usability/">Extensive Guide To Web Form Usability</a>.</li> + <li>UXMatters 도 좋은 폼 양식을 볼수 있다. <a href="http://www.uxmatters.com/mt/archives/2012/05/7-basic-best-practices-for-buttons.php" rel="external" title="http://www.uxmatters.com/mt/archives/2012/05/7-basic-best-practices-for-buttons.php">basic best practices</a> 의 <a href="http://www.uxmatters.com/mt/archives/2010/03/pagination-in-web-forms-evaluating-the-effectiveness-of-web-forms.php" title="http://www.uxmatters.com/mt/archives/2010/03/pagination-in-web-forms-evaluating-the-effectiveness-of-web-forms.php">multi-page forms</a>.</li> +</ul> + +<p>이 문서에서는 간단한 문의를 하는 폼을 만들것이다. 거칠게 스케치 해보자.</p> + +<p><img alt="The form to build, roughly sketch" src="/files/4579/form-sketch-low.jpg" style="border-style: solid; border-width: 1px; height: 352px; width: 400px;"></p> + +<p>우리가 만들 폼은 3개의 텍스트 필드와 하나의 버튼을 가지고 있다. 기본적으로 우리는 사용자에게 이름, 이메일, 문의사항을 물어 볼 것이고 버튼을 눌러서 웹서버로 데이터를 보내는게 목적이다.</p> + +<h2 id="HTML를_직접_다루어_보자" style="line-height: 30px;">HTML를 직접 다루어 보자</h2> + +<p>자 이제 HTML에가서 폼을 코딩 할 준비가 되었다. 우리의 문의하는 폼에서 다음과 같은 HTML 요소들을 사용할 것이다. {{HTMLElement("form")}}, {{HTMLElement("label")}}, {{HTMLElement("input")}}, {{HTMLElement("textarea")}}, and {{HTMLElement("button")}}.</p> + +<h3 id="HTMLElement(form)_요소" style="line-height: 24px;">{{HTMLElement("form")}} 요소</h3> + +<p>모든 HTML 폼은 {{HTMLElement("form")}} 요소로 다음과 같이 시작된다:</p> + +<pre class="brush:html;" style="font-size: 14px;"><form action="/my-handling-form-page" method="post"> + +</form></pre> + +<p>이 요소는 폼의 공식적인 형태이다. 이 요소는 다음 {{HTMLElement("div")}} 나 {{HTMLElement("p")}} 요소와 같이 사용되고,뿐만 아니라 폼이 동작하는 방식을 설정하는 일부 속성들을 지정 해야한다. 이러한 모든 속성은 선택적이지만 <code style="font-size: 14px;">action</code> 속성과 <code style="font-size: 14px;">method</code> 속성은 필수적으로 설정해야 한다.</p> + +<ul> + <li><code style="font-size: 14px;">action</code> 속성은 데이터를 보낼 URL을 지정한다.</li> + <li><code style="font-size: 14px;">method</code> 속성은 어떤 HTTP 방식을 사용할 것인지 지정한다.(GET 이나 POST)</li> +</ul> + +<p>만약 이러한 속성에 더 자세한 내용을 알고 싶다면 다음 문서를 참조하시오. <a href="/en-US/docs/HTML/Forms/Sending_and_retrieving_form_data" title="/en-US/docs/HTML/Forms/Sending_and_retrieving_form_data">Sending and retrieving form data</a>.</p> + +<h3 id="HTMLElement(label)_HTMLElement(input)_그리고_HTMLElement(textarea)_요소_추가하기" style="line-height: 24px;">{{HTMLElement("label")}}, {{HTMLElement("input")}}, 그리고 {{HTMLElement("textarea")}} 요소 추가하기</h3> + +<p>우리의 문의하는 폼은 정말 간단하고 라벨을 가지고 있는 세 개의 텍스트필드를 가지고 있다. 이름을 입력 받는 입력 필드는 한줄 텍스트 필드를 사용하고, 이메일을 입력 받는 입력 필드는 이메일만 입력받는 한줄 텍스트 필드를 사용하고, 문의 내용을 입력받는 입력 필드는 다중 라인 텍스트 필드가 사용 될것이다.</p> + +<p>HTML코드를 다음과 같이 짤 것이다.</p> + +<pre class="brush:html;" style="font-size: 14px;"><form action="/my-handling-form-page" method="post"> + <div> + <label for="name">Name:</label> + <input type="text" id="name" /> + </div> + <div> + <label for="mail">E-mail:</label> + <input type="email" id="mail" /> + </div> + <div> + <label for="msg">Message:</label> + <textarea id="msg"></textarea> + </div> +</form></pre> + +<p>{{HTMLElement("div")}} 요소는 코드를 편리하게 구성하고 스타일링 쉽게 만들어 줍니다. 중요한 점은 for속성은 모든{{HTMLElement("label")}} 요소에서 공식적으로 폼 위젯과 라벨을 연결하는데 사용된는 것이다. 이 속성은 위젯에 맞는 ID를 참조한다. 이 것은 몇 가지 장점이 있다. 가장 두드러 지는 것은 사용자가 라벨을 눌럿을때 그거에 맞는 위젯을 활성화 시키는 것이다.만약 이 속성에 대한 장점을 더 알고 싶다면 다음 문서에 자세히 나와있다. <a href="/en-US/docs/HTML/Forms/How_to_structure_an_HTML_form" title="/en-US/docs/HTML/Forms/How_to_structure_an_HTML_form">How to structure an HTML form</a>.</p> + +<p>{{HTMLElement("input")}} 요소의 가장 중요한 속성은 type 속성이다. 이 속성은 {{HTMLElement("input")}} 요소가 어떻게 입력을 받을 것인지 정의하기 떄문에 매우 중요하다. 이것은 아예 요소를 변경하기 떄문에 주의 해야한다. 만약 이것에 대하여 더 자세한 정보를 알고 싶다면 다음 문서를 참조 하라. <a href="/en-US/docs/HTML/Forms/The_native_form_widgets" rel="external" title="/en-US/docs/HTML/Forms/The_native_forms_widgets">native form widgets</a> 우리의 예제에서는 이 속성의 기본 값인 오직 <span style="font-family: 'Courier New','Andale Mono',monospace; line-height: normal;">text</span><span style="line-height: 1.5;">값만 사용했다.</span><span style="line-height: 1.5;"> </span>이 값은 제어나 유효성 검사 없이 모든 종류의 텍스트를 받아 들이는 한줄 텍스트 필드를 나타낸다.<span style="line-height: 1.5;"> </span>또한 오직 이메일 주소만 받는 한줄 텍스트 필드 <span style="font-family: 'Courier New','Andale Mono',monospace; line-height: normal;">email</span>값을 사용했다.<span style="line-height: 1.5;"> </span>이 마지막 값은 기본 텍스트 필드를 사용자가 입력 한 데이터에 대한 몇 가지 검사를 수행하는 "지능형"필드의 종류로 전환한다<span style="line-height: 1.5;">. 만약 폼 데이터 유효성 확인에 대하여 자세히 알고싶다면 다음 문서를 참조 해라. </span><a href="/en-US/docs/HTML/Forms/Data_form_validation" style="line-height: 1.5;" title="/en-US/docs/HTML/Forms/Data_form_validation">Form data validation</a></p> + +<p>마지막 요소를 보기전에 다음 <code style="font-size: 14px;"><input /></code> VS <code style="font-size: 14px;"><textarea></textarea>요소를 봐야한다</code>. 이것은 이상한 HTML 요소중 하나이다. <code style="font-size: 14px;"><input>태그는 자동 닫힘 태그다 무슨 의미냐면</code> 요소가 끝날떄 반드시 "/"닫는 태그에 추가해야 하는 것을 의미한다. 이와 반대로, {{HTMLElement("textarea")}}은 자동 닫힘 태그가 아니다 그래서 반드시 엔딩태그를 사용하여 요소를 종료해야한다. 이 것은 기본 값을 정의하는 특정 기능에 영향을 미친다. <span style="line-height: 1.5;">요소의 기본 값 정의는 반드시 value 속성을 다음과 같이 지정 해야 한다.</span></p> + +<pre class="brush:html;" style="font-size: 14px;"><input type="text" value="by default this element is filled with this text" /></pre> + +<p>이와 반대로 {{HTMLElement("textarea")}}요소 에서 기본값을 정의하고 싶다면, {{HTMLElement("textarea")}}요소의 시작 태그와 끝 태그 사이에 문자들을 다음과 같이 입력 하면된다.</p> + +<pre class="brush:html;" style="font-size: 14px;"><textarea>by default this element is filled with this text</textarea></pre> + +<h3 id="HTMLElement(button)_요소로_끝내기" style="line-height: 24px;"> {{HTMLElement("button")}} 요소로 끝내기</h3> + +<p>우리의 폼이 거의 완성되간다. 이제 단지 사용자 데이터를 서버에 보낼수 있도록 버튼을 추가하면된다. 이것은 간단하게 {{HTMLElement("button")}} 요소를 사용한다.</p> + +<pre class="brush:html;" style="font-size: 14px;"><form action="/my-handling-form-page" method="post"> + <div> + <label for="name">Name:</label> + <input type="text" id="name" /> + </div> + <div> + <label for="mail">E-mail:</label> + <input type="email" id="mail" /> + </div> + <div> + <label for="msg">Message:</label> + <textarea id="msg"></textarea> + </div> + + <div class="button"> + <button type="submit">Send your message</button> + </div> +</form></pre> + +<p>버튼은 다음과 같은 3개 종류가 있다. <code style="font-size: 14px;">submit</code>, <code style="font-size: 14px;">reset</code>, <code style="font-size: 14px;">button</code>.</p> + +<ul> + <li><span style="font-family: 'Courier New','Andale Mono',monospace; line-height: normal;">submit</span> 버튼을 클릭하면 폼 데이터를 {{HTMLElement("form")}} 요소의 <span style="font-family: 'Courier New','Andale Mono',monospace; line-height: normal;">action</span>속성에 정의된 웹페이지 에 전송된다.</li> + <li> <code style="font-size: 14px;">reset</code> 버튼을 클릭하면 모든 폼 위젯을 기본 값으로 바꾼다. UX 관점에서 이방법은 안좋은 방법이라 본다.</li> + <li><code style="font-size: 14px;">button 버튼은... 아무것도 안한다! 이 말이 이상하게 들릴수도 있지만 JavaScript를 사용하면 놀랍게 유용한 사용자 버튼이 될 수 있다.</code></li> +</ul> + +<p>알아두어야 할것은 {{HTMLElement("input")}} 요소를 사용하여 버튼 유형을 만들 수 있다. {{HTMLElement("button")}}요소와 가장 큰 차이점은 {{HTMLElement("input")}}요소는 오직 일반 텍스트만 보내는 반면 {{HTMLElement("button")}}요소는 전체 HTML 콘텐츠를 보낸다.</p> + +<h2 id="CSS로_더욱_나이스하게_만들기" style="line-height: 30px;">CSS로 더욱 나이스하게 만들기</h2> + +<p>이제 우리는 HMLT폼을 가졋지만 가지고 있는 브라우저에서 보면 구리게 보인다.</p> + +<p><img alt="" src="/files/4049/form-no-style.png" style="height: 170px; width: 534px;"></p> + +<p>CSS 스타일시트를 이용하여 조금만더 나이스하게 만들어 보자.</p> + +<p>폼을 가운데로 정렬하고 테두리를 보이게 하는것 부터 시작하자.</p> + +<pre class="brush:css;" style="font-size: 14px;">form { + /* Just to center the form on the page */ + margin: 0 auto; + width: 400px; + /* To see the outline of the form */ + padding: 1em; + border: 1px solid #CCC; + border-radius: 1em; +}</pre> + +<p>그 다음 각각 폼 위젯사이에 여백을 추가하자.</p> + +<pre class="brush:css;" style="font-size: 14px;">form div + div { + margin-top: 1em; +}</pre> + +<p>이제 레이블에 초점을 맞추자. 우리의 폼을 더 읽기 쉽게 만들기 위해 모든 라벨들이 같은 사이즈와 같은 쪽을 정렬이 되게하자. 이 경우 오른쪽 정렬을 하지만 경우에 따라서 왼쪽 정렬도 좋을 수 있다.</p> + +<pre class="brush:css;" style="font-size: 14px;">label { + /* To make sure that all label have the same size and are properly align */ + display: inline-block; + width: 90px; + text-align: right; +}</pre> + +<p>HTML 폼을 다루는 가장 어려운 것중 하나는 HTML자체를 위젯으로 스타일 하는 것이다. 텍스트 필드는 쉽게 스타일 할수 있지만 다른 위젯들은 아니다. 만약 HTML 폼 위젯 스타일에 대하여 자세한 정보를 알고 싶으면 다음 문서를 참조하시오. <a href="/en-US/docs/HTML/Forms/Styling_HTML_forms" title="/en-US/docs/HTML/Forms/Styling_HTML_forms">Styling HTML forms</a></p> + +<p>폰트, 크기, 테두리를 변경 해보자</p> + +<pre class="brush:css;" style="font-size: 14px;">input, textarea { + /* To make sure that all text fields have the same font settings + By default, textareas have a monospace font */ + font: 1em sans-serif; + + /* To give the same size to all text field */ + width: 300px; + -moz-box-sizing: border-box; + box-sizing: border-box; + + /* To harmonize the look & feel of text field border */ + border: 1px solid #999; +}</pre> + +<p>HTML 폼은 요소의 상태를 나타내는 많은 가상클래스 를 지원한다.예르들어 위젯이 활성화 되면 하이라이트 효과를 추가할 수있다. 이것은 사용자가 쉽게 따라가도록 하는 편리한 방법이다.</p> + +<pre class="brush:css;" style="font-size: 14px;">input:focus, textarea:focus { + /* To give a little highlight on active elements */ + border-color: #000; +}</pre> + +<p>다중 텍스트 필드는 몇몇 사용자 지정 스타일이 필요하다. 기본적으로 {{HTMLElement("textarea")}}요소는 바닥이 텍스트 기준선에 정렬되는 인라인 블록 이다. 대부분 이것들은 우리가 원하는 것이 아니다. 이런 경우 나이스하게 라벨과 필드를 정렬하려면 {{HTMLElement("textarea")}}요소의 <code style="font-size: 14px;">vertical-align</code><span style="line-height: 1.5;"> 속성을 </span><span style="line-height: 1.5;"> </span><code style="font-size: 14px;">top이라 변경 해야 한다</code><span style="line-height: 1.5;">.</span></p> + +<p>또하나 유용한 <code style="font-size: 14px;">resize</code> 프로퍼티는 사용자가 쉽게 {{HTMLElement("textarea")}}요소의 크기를 조정 할수 있게 해준다.</p> + +<pre class="brush:css;" style="font-size: 14px;">textarea { + /* To properly align multiline text fields with their labels */ + vertical-align: top; + + /* To give enough room to type some text */ + height: 5em; + + /* To allow users to resize any textarea vertically + It does not work on every browsers */ + resize: vertical; +}</pre> + +<p>버튼도 특별한 스타일이 필요하다. <span style="line-height: 1.5;">이를 위해 우선 {{HTMLElement("div")}}요소안에 버튼을 넣는다. 그리고 다른 위젯들과 정렬을 해야한다. 그럴러면 {{HTMLElement("label")}}요소를 흉내 내야한다. 그 후에 패딩 과 마진 속성을 지정하면된다</span></p> + +<pre class="brush:css;" style="font-size: 14px;">.button { + /* To position the buttons to the same position of the text fields */ + padding-left: 90px; /* same size as the label elements */ +} + +button { + /* This extra margin represent roughly the same space as the space + between the labels and their text fields */ + margin-left: .5em; +}</pre> + +<p>이제 폼이 더 나이스 해졋다.</p> + +<p><img alt="" src="/files/4051/form-style.png" style="height: 260px; width: 900px;"></p> + +<h2 id="웹서버로_데이터_보내기" style="line-height: 30px;">웹서버로 데이터 보내기</h2> + +<p>까다로울지 모르는 마지막 부분은 데이터를 서버측에서 처리하는 것이다. 앞에서 언급 된 바와 같이 HTML폼은 사용자에게 데이터를 물어보고 웹서버로 데이터를 전달하는 데 편리한 방법이다.</p> + +<p>{{HTMLElement("form")}} 요소는 <span style="font-family: 'Courier New','Andale Mono',monospace; line-height: normal;">action속성과 </span><span style="font-family: 'Courier New','Andale Mono',monospace; line-height: normal;">method속성을 </span><span style="line-height: 1.5;">사용하여 데이터를 어디에 어떻게 보낼것인지 정의한다.</span></p> + +<p>이걸로 충분하지않다. 데이터의 이름을 지정해야한다. 이러한 이름들은 브라우저측이나 서버 측 모두에게 중요하다. 브라우저에게는 데이터 각 부분에는 이름을 지정하고 서버측 에서는 이름을 이용하여 데이터를 다룰수 있게 해준다.</p> + +<p>그래서 데이터의 이름을 지정하려면 데이터를 받는 각 폼 위젯에 <span style="font-family: 'Courier New','Andale Mono',monospace; line-height: normal;">name</span><span style="line-height: 1.5;">속성을 지정해야한다.</span></p> + +<pre class="brush:html;" style="font-size: 14px;"><form action="/my-handling-form-page" method="post"> + <div> + <label for="name">Name:</label> + <input type="text" id="name" name="user_name" /> + </div> + <div> + <label for="mail">E-mail:</label> + <input type="email" id="mail" name="user_email" /> + </div> + <div> + <label for="msg">Message:</label> + <textarea id="msg" name="user_message"></textarea> + </div> + + <div class="button"> + <button type="submit">Send your message</button> + </div> +</form></pre> + +<p>우리의 예제에서는 다음과 같이 3가지 데이터 이름을 지정했다. "<code style="font-size: 14px;">user_name</code>", "<code style="font-size: 14px;">user_email</code>" and "<code style="font-size: 14px;">user_message</code>". 이 데이터는 "<code style="font-size: 14px;">/my-handling-form-page</code>"로 HTTP POST 방식으로 전송된다.</p> + +<p><span style="line-height: 1.5;">서버 측에서는 URL에서 HTTP 요청에 의해 구현된 3개의 키/벨류 항목의 목록 데이터를 받게 된다. </span>스크립트로 데이터를 다루는 방법은 너에게 달려있다. 각각 의 서버 측 언어들은(PHP, Python, Ruby, Java, C# 등)자신만의 방식으로 이를 다룬다. 더 깊게 들어가는 것은 이문서의 범위를 벗어나지만 더자세히 알고 싶다면 다음 문서를 참조하시오. <a href="/en-US/docs/HTML/Forms/Sending_and_retrieving_form_data" title="/en-US/docs/HTML/Forms/Sending_and_retrieving_form_data">Sending and retrieving form data</a>.</p> + +<h2 id="결론" style="line-height: 30px;">결론</h2> + +<p>축하한다! 첫번째 HTML폼을 만들었다.</p> + +<table> + <thead> + <tr> + <th scope="col" style="text-align: center;">Live example</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{ EmbedLiveSample('A_simple_form', '100%', '240', '', 'Learn/HTML/Forms/Your_first_HTML_form/Example') }}</td> + </tr> + <tr> + <td style="text-align: center;"><a href="/en-US/docs/HTML/Forms/My_first_HTML_form/Example" title="/en-US/docs/HTML/Forms/My_first_HTML_form/Example">Check out the source code</a></td> + </tr> + </tbody> +</table> + +<p>하지만 이제 시작일 뿐이고, 더 깊게 파고들 시간이다. HTML폼은 이 문서에서 본 것 보다 더 강력한 도구이고, 이 가이드의 다른 문서가 나머지 내용을 배우는데 도움이 될 것이다.</p> + +<p>{{NextMenu("Learn/HTML/Forms/How_to_structure_an_HTML_form", "Learn/HTML/Forms")}}</p> diff --git a/files/ko/learn/html/howto/index.html b/files/ko/learn/html/howto/index.html new file mode 100644 index 0000000000..2bef079e90 --- /dev/null +++ b/files/ko/learn/html/howto/index.html @@ -0,0 +1,153 @@ +--- +title: Learn HTML to solve problems +slug: Learn/HTML/Howto +tags: + - CodingScripting + - HTML + - NeedsTranslation + - TopicStub +translation_of: Learn/HTML/Howto +--- +<p>Once you've covered <a href="/en-US/Learn/Getting_started_with_the_web/HTML_basics">the basics</a>, there isn't one right path to learn {{Glossary("HTML")}}. You can pick up whatever you like at your own pace. HTML is simply a set of {{glossary("tag","tags")}} you can use to set up your document structure and add extra functionality to your document. The following articles explain thoroughly, with full working examples, how to use HTML for the most common, frequent Web development tasks. If you need a quick explanation of a tag, please head over to our <a href="/en-US/docs/Web/HTML/Reference">HTML reference</a>.</p> + +<h2 id="Common_use_cases">Common use cases</h2> + +<p>HTML covers a lot of very common use cases in Web design. It's highly likely you'll come across these scenarios:</p> + +<div class="column-container"> +<div class="column-half"> +<h3 id="Basic_structure">Basic structure</h3> + +<p>The most basic application of HTML is document structure. If you're new to HTML you should start with this.</p> + +<ul> + <li><a href="/en-US/docs/Learn/HTML/Howto/Create_a_basic_HTML_document">How to create a basic HTML document</a></li> + <li><a href="/en-US/docs/Learn/HTML/Howto/Divide_a_webpage_into_logical_sections">How to divide a webpage into logical sections</a></li> + <li><a href="/en-US/docs/Learn/HTML/Howto/Set_up_a_proper_title_hierarchy">How to set up a proper title hierarchy</a></li> +</ul> + +<h3 id="Basic_text-level_semantics">Basic text-level semantics</h3> + +<p>HTML specializes in providing semantic information for a document, so HTML answers many questions you might have about how to get your message across best in your document.</p> + +<ul> + <li><a href="/en-US/docs/Learn/HTML/Howto/Create_list_of_items_with_HTML">How to create list of items with HTML</a></li> + <li><a href="/en-US/docs/Learn/HTML/Howto/Emphasize_content_or_indicate_that_text_is_important">How to stress or emphasize content</a></li> + <li><a href="/en-US/docs/Learn/HTML/Howto/Emphasize_content_or_indicate_that_text_is_important">How to indicate that text is important</a></li> + <li><a href="/en-US/docs/Learn/HTML/Howto/Display_computer_code_with_HTML">How to display computer code with HTML</a></li> + <li><a href="/en-US/docs/Learn/HTML/Howto/Indicate_exponential_notation_with_HTML">How to indicate exponential notation with HTML</a></li> + <li><a href="/en-US/docs/Learn/HTML/Howto/Provide_contact_information_within_a_webpage">How to provide contact information within a webpage</a></li> + <li><a href="/en-US/docs/Learn/HTML/Howto/Annotate_images_and_graphics">How to annotate images and graphics</a></li> + <li><a href="/en-US/docs/Learn/HTML/Howto/Mark_abbreviations_and_make_them_understandable">How to mark abbreviations and make them understandable</a></li> + <li><a href="/en-US/docs/Learn/HTML/Howto/Add_citations_to_webpages">How to add citations to webpages</a></li> + <li><a href="/en-US/docs/Learn/HTML/Howto/Define_terms_with_HTML">How to define terms with HTML</a></li> +</ul> +</div> + +<div class="column-half"> +<h3 id="Hyperlinks">Hyperlinks</h3> + +<p>One of the main reasons for HTML is make navigation easy with {{Glossary("hyperlink", "hyperlinks")}}, which can be used in many different ways:</p> + +<ul> + <li><a href="/en-US/docs/Learn/HTML/Howto/Create_a_hyperlink">How to create a hyperlink</a></li> + <li><a href="/en-US/docs/Learn/HTML/Howto/Create_list_of_items_with_HTML">How to create a table of contents with HTML</a></li> +</ul> + +<h3 id="Images_multimedia">Images & multimedia</h3> + +<ul> + <li><a href="/en-US/docs/Learn/HTML/Howto/Add_images_to_a_webpage">How to add images to a webpage</a></li> + <li><a href="/en-US/docs/Learn/HTML/Howto/Add_audio_or_video_content_to_a_webpage">How to add video content to a webpage</a></li> + <li><a href="/en-US/docs/Learn/HTML/Howto/Add_audio_or_video_content_to_a_webpage">How to add audio content to a webpage</a></li> +</ul> + +<h3 id="Scripting_styling">Scripting & styling</h3> + +<p>HTML only sets up document structure. To solve presentation issues, use {{glossary("CSS")}}, or use scripting to make your page interactive.</p> + +<ul> + <li><a href="/en-US/docs/Learn/HTML/Howto/Use_CSS_within_a_webpage">How to use CSS within a webpage</a></li> + <li><a href="/en-US/docs/Learn/HTML/Howto/Use_JavaScript_within_a_webpage">How to use JavaScript within a webpage</a></li> +</ul> + +<h3 id="Embedded_content">Embedded content</h3> + +<ul> + <li><a href="/en-US/docs/Learn/HTML/Howto/Embed_a_webpage_within_another_webpage">How to embed a webpage within another webpage</a></li> + <li><a href="/en-US/docs/Learn/HTML/Howto/Add_Flash_content_within_a_webpage">How to add Flash content within a webpage</a></li> +</ul> +</div> +</div> + +<h2 id="Uncommon_or_advanced_problems">Uncommon or advanced problems</h2> + +<p>Beyond the basics, HTML is very rich and offers advanced features for solving complex problems. These articles help you tackle the less common use cases you may face:</p> + +<div class="column-container"> +<div class="column-half"> +<h3 id="Forms">Forms</h3> + +<p>Forms are a complex HTML structure made to send data from a webpage to a web server. We encourage you to go over our <a href="/en-US/docs/Web/Guide/HTML/Forms">full dedicated guide</a>. Here is where you should start:</p> + +<ul> + <li><a href="/en-US/docs/Web/Guide/HTML/Forms/My_first_HTML_form">How to create a simple Web form</a></li> + <li><a href="/en-US/docs/Web/Guide/HTML/Forms/How_to_structure_an_HTML_form">How to structure a Web form</a></li> +</ul> + +<h3 id="Tabular_information">Tabular information</h3> + +<p>Some information, called tabular data, needs to be organized into tables with columns and rows. It's one of the most complex HTML structures, and mastering it is not easy:</p> + +<ul> + <li><a href="/en-US/docs/Learn/HTML/Howto/Create_a_data_spreadsheet">How to create a data spreadsheet</a></li> + <li><a href="/en-US/docs/Learn/HTML/Howto/Make_HTML_tables_accessible">How to make HTML tables accessible</a></li> + <li><a href="/en-US/docs/Learn/HTML/Howto/Optimize_HTML_table_rendering">How to optimize HTML table rendering</a></li> +</ul> + +<h3 id="Data_representation">Data representation</h3> + +<ul> + <li><a href="/en-US/docs/Learn/HTMLHowto/Represent_numeric_values_with_HTML">How to represent numeric values with HTML</a></li> + <li><a href="/en-US/docs/Learn/HTML/Howto/Associate_human_readable_content_with_arbitrary_computer_data_structures">How to associate human readable content with arbitrary computer data structures</a></li> +</ul> + +<h3 id="Interactivity">Interactivity</h3> + +<ul> + <li><a href="/en-US/docs/Learn/HTML/Howto/Create_collapsible_content_with_HTML">How to create collapsible content with HTML</a></li> + <li><a href="/en-US/docs/Learn/HTML/Howto/Add_context_menus_to_a_webpage">How to add context menus to a webpage</a></li> + <li><a href="/en-US/docs/Learn/HTML/Howto/Create_dialog_boxes_with_HTML">How to create dialog boxes with HTML</a></li> +</ul> +</div> + +<div class="column-half"> +<h3 id="Advanced_text_semantics">Advanced text semantics</h3> + +<ul> + <li><a href="/en-US/docs/Learn/HTML/Howto/Take_control_of_HTML_line_breaking">How to take control of HTML line breaking</a></li> + <li><a href="/en-US/docs/Learn/HTML/Howto/Mark_text_insertion_and_deletion">How to mark changes (added and removed text)</a></li> +</ul> + +<h3 id="Advanced_images_multimedia">Advanced images & multimedia</h3> + +<ul> + <li><a href="/en-US/docs/Learn/HTML/Howto/Add_responsive_image_to_a_webpage">How to add responsive image to a webpage</a></li> + <li><a href="/en-US/docs/Learn/HTML/Howto/Add_vector_image_to_a_webpage">How to add vector image to a webpage</a></li> + <li><a href="/en-US/docs/Learn/HTML/Howto/Add_a_hit_map_on_top_of_an_image">How to add a hit map on top of an image</a></li> + <li><a href="/en-US/docs/Learn/HTML/Howto/Create_dynamic_and_interactive_images">How to create dynamic and interactive images</a></li> +</ul> + +<h3 id="Internationalization">Internationalization</h3> + +<p>HTML is not monolingual. It provides tools to handle common internationalization issues.</p> + +<ul> + <li><a href="/en-US/docs/Learn/HTML/Howto/Add_multiple_languages_into_a_single_webpage">How to add multiple languages into a single webpage</a></li> + <li><a href="/en-US/docs/Learn/HTML/Howto/Handle_Japanese_ruby_characters">How to handle Japanese ruby characters</a></li> + <li><a href="/en-US/docs/Learn/HTML/Howto/Display_time_and_date_with_HTML">How to display time and date with HTML</a></li> +</ul> +</div> +</div> + +<p><span style="display: none;"> </span><span style="display: none;"> </span><span style="display: none;"> </span><span style="display: none;"> </span> </p> diff --git a/files/ko/learn/html/howto/mark_abbreviations_and_make_them_understandable/index.html b/files/ko/learn/html/howto/mark_abbreviations_and_make_them_understandable/index.html new file mode 100644 index 0000000000..41c1697de3 --- /dev/null +++ b/files/ko/learn/html/howto/mark_abbreviations_and_make_them_understandable/index.html @@ -0,0 +1,267 @@ +--- +title: 약자 표시 및 이해시키는 방법 +slug: Learn/HTML/Howto/Mark_abbreviations_and_make_them_understandable +tags: + - HTML + - 초보 +translation_of: Learn/HTML/Introduction_to_HTML/Advanced_text_formatting#Abbreviations +--- +<div class="summary"> +<p>HTML은 독자가 이해할 수 있도록 해주는 약자를 표시해주는 단순하고 직관적인 방법을 제공합니다.</p> +</div> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">먼저:</th> + <td><a href="/en-US/Learn/HTML/Write_a_simple_page_in_HTML">기초적인 HTML 문서 만들기</a>에 익숙해지셔야 합니다.</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>HTML로 어떻게 약자 및 두음문자를 표시하는지 알아봅시다.</td> + </tr> + </tbody> +</table> + +<h2 id="약자에_대해">약자에 대해</h2> + +<p>항상 우리는 글을 쓸 때 약자나 두음문자를 사용합니다.('중화인민공화국'의 '중국'같이 짧게 적는 것이 약자, '아껴쓰고, 나눠쓰고, 바꿔쓰고, 다시쓰고'의 '아나바다'와 같이 첫 글자만 골라서 쓰는 것이 두음문자입니다.)</p> + +<p>We have to make sure that our readers can understand our abbreviations. In standard writing, it's really common to spell out the abbreviation only on its first occurrence, then just use the abbreviation everywhere:</p> + +<blockquote>유럽연합(UE)은 28 개의 주로, 합중국(US)은 50 개의 주로 이루어져 있습니다. US는 연방제 공화국, UE는 자치주들이 정치적, 경제적으로 결속한 집단입니다.</blockquote> + +<div> +<p>이렇게 하면 모든 웹 페이지에 완전히 유효하지만, HTML은 독자들에게 약자를 설명하기 위한 부가적인 방법을 제공해줍니다.</p> +</div> + +<h2 id="abbr_요소">abbr 요소</h2> + +<p><em>HTML 약자 요소</em> ({{HTMLElement("abbr")}})는 약자에 익숙하지 않거나 시각장애우같이 스크린 리더를 실행해야 하는 사람들을 돕기 위한 약자나 두음문자를 말합니다. 가장 중요한 규칙은, 가능한 언제든지 쓰라는 것입니다.</p> + +<div class="note"> +<p><strong>알림:</strong> <code><acronym></code> 요소에 대해 들어보셨겠지만, <code><acronym</code><code>></code>은 사장되었으므로 브라우저에서 언제든지 지원을 끊을 수 있기 때문에 사용하지 말아야 합니다.</p> +</div> + +<pre class="brush: html"><p>I need to talk to you <abbr>ASAP</abbr>.</p></pre> + +<p>이렇게 <code>title</code> 속성으로 약자를 설명할 수도 있습니다:</p> + +<pre class="brush: html"><p>I need to talk to you <abbr title="as soon as possible">ASAP</abbr>.</p></pre> + +<p>언제 <code>title</code> 속성을 적어야 할까요? 마음대로 시면 됩니다. It can be overkill to spell out a very common abbreviation like "ASAP" or an abbreviation used many times in your document. When in doubt, err on the side of providing the full description.</p> + +<div class="note"> +<p><strong>Note: </strong>In languages with grammatical number (especially languages with more than two numbers, like Arabic), use the same grammatical number in your <code>title</code> attribute as inside your <code><abbr></code> element.</p> +</div> + +<p>{{glossary("CSS")}}로 약자를 가리키는 가시적인 정보를 추가, 변경, 제거하실 수 있습니다. 보통 마우스를 대면 브라우저가 <code>title</code> 속성의 콘텐츠를 툴팁으로 보여준다는 것도 기억하십시오. 이전의 예시대로 하면 이렇게 보여집니다:</p> + +<p>{{ EmbedLiveSample('The_abbr_element','100%',90) }}</p> + +<div class="note"> +<p><strong>중요: </strong>만약 사람들이 약자를 이해하는 것을 따진다면, <strong>절대로</strong> <code>title</code> 속성에 의존하지 마세요. Spell your abbreviation out in the text on first occurrence. 툴팁에 접근하려면 마우스가 필요합니다. 이것은 폰이나 키보드, 스크린 리더를 쓰는 사람들을 배제합니다.</p> +</div> + +<h2 id="실전">실전</h2> + +<p>{{HTMLElement('abbr')}}에 대해 알아봅시다. 이 글 바로 밑에 약자를 <code><abbr></code>로 표시하고 <code>title</code> 속성으로 설명합니다. 다 했으면 잘 되었는지 보기 위해 "show results"를 눌러봅시다. <a href="/en-US/docs/Glossary">용어 사전</a>에서 모든 약자들을 보실 수 있습니다.</p> + +<div class="hidden"> +<pre class="brush: html"><div class="exercise"> + <main> + <div class="instruction">Mark all the abbreviations with the <code>&lt;abbr&gt;</code> element</div> + <div class="playground"><textarea spellcheck="false"></textarea></div> + <div class="checking"> + <button>Show results</button><span class="count"></span> + </div> + <div class="result">Web <abbr title="developers">dev.</abbr> use <abbr title="Hypertext Markup Language">HTML</abbr> to structure documents, <abbr title="Cascading StyleSheet">CSS</abbr> to style them, and JavaScript to add special effects by using some dedicated <abbr title="Application Programming Interface">API</abbr>s.</div> + </main> +</div></pre> + +<pre class="brush: css">body { + font: 1em/100% sans-serif; + padding: 0; + margin: 0; +} + +.exercise { + background: #F9FAFB; + border-radius: 5px; + height: 13em; + overflow: hidden; +} + +.instruction, .count { + padding: .5em; + font-style: italic; + font-size: .95em; +} + +.playground { + padding: 0 .5em; +} + +.playground textarea { + display: block; + font-size : 1em; + line-height: 1.5em; + font-family: monospace; + box-sizing: border-box; + width : 100%; + padding : .5em; + height : 9.7em; +} + +.checking { + padding: .5em; +} + +.checking button { + box-sizing: border-box; + box-shadow:inset 0 1px 0 0 #bcd9a3; + background:linear-gradient(to bottom, #b4d665 5%, #89a646 100%); + background-color:#b4d665; + border-radius:5px; + border:1px solid #8aa164; + cursor:pointer; + font-size:1em; + padding:.5em; + text-decoration:none; +} +.checking button:hover { + background:linear-gradient(to bottom, #89a646 5%, #b4d665 100%); + background-color:#89a646; +} +.checking button:active { + transform: translate(0, 1px); +} + +.result { + height: 10em; + line-height: 1.4em; + padding: .5em; + box-sizing: border-box; +} + +main { + transform: translate(0,0); + transition: transform 300ms; +} + +.next main { + transform: translate(0, -10em); +} + +abbr { + display: inline-block; + white-space: nowrap; +} + +abbr.ok { + color: green; +} + +abbr.ok:after { + content: ' ✔︎'; +} + +abbr.fail { + color: red; +} + +abbr.fail:after { + content: ' ✘'; +} + +abbr.warning { + color: orange; +} + +abbr.warning:after { + content: ' !'; + font-weight: bold; +} +</pre> + +<pre class="brush: js">window.addEventListener('load', function () { + var content = document.querySelector('.exercise'); + var input = document.querySelector('.playground textarea'); + var button = document.querySelector('.checking button'); + var message = document.querySelector('.checking .count'); + var abbr = Array.prototype.slice.call(document.querySelectorAll('.result abbr')); + var data = { + pass : 0, fail : 0, warning : 0 + }; + + input.value = document.querySelector('.result').textContent; + + function toggleResult(e) { + e.preventDefault(); + var classList = content.className.split(' '); + + if (classList.length === 1 && checkResult()) { + content.className = 'exercise next'; + message.innerHTML = 'Get ' + data.pass + ', ' + + 'Get ' + data.warning + ' without full description, ' + + 'Miss ' + data.fail + '.'; + button.innerHTML = 'Try again'; + } else { + content.className = 'exercise'; + message.innerHTML = ''; + button.innerHTML = 'Show results'; + } + } + + function checkResult() { + var i, j, node = document.createElement('div'); + node.innerHTML = input.value; + data = { pass : 0, fail : 0, warning : 0 }; + + var userAbbr = Array.prototype.slice.call(node.querySelectorAll('abbr')); + + if (userAbbr.length === 0) { + alert("You haven't marked any abbreviations (there are " + abbr.length + " to find)."); + return false; + } + + for (i in abbr) { + var txt = abbr[i].textContent; + var fail = true; + + for (j in userAbbr) { + var userText = userAbbr[j].textContent; + + if (userText.match(new RegExp('^\\s*' + txt.replace('.','') + '\\s*$'))) { + fail = false; + if (userAbbr[j].title) { + data.pass += 1; + abbr[i].className = 'ok'; + } else { + data.warning += 1; + abbr[i].className = 'warning'; + } + } + } + + if (fail) { + data.fail += 1; + abbr[i].className = 'fail'; + } + } + + return true; + } + + button.addEventListener('click', toggleResult); +}); +</pre> +</div> + +<p>{{ EmbedLiveSample('Exercise','100%',220) }}</p> + +<h2 id="더_알아보기">더 알아보기</h2> + +<ul> + <li>{{HTMLElement("abbr")}} 참고 문서.</li> +</ul> diff --git a/files/ko/learn/html/howto/데이터_속성_사용하기/index.html b/files/ko/learn/html/howto/데이터_속성_사용하기/index.html new file mode 100644 index 0000000000..d4abd5da57 --- /dev/null +++ b/files/ko/learn/html/howto/데이터_속성_사용하기/index.html @@ -0,0 +1,82 @@ +--- +title: 데이터 속성 사용하기 +slug: Learn/HTML/Howto/데이터_속성_사용하기 +tags: + - HTML + - HTML5 + - 가이드 + - 예제 + - 웹 + - 전용 데이터 속성 +translation_of: Learn/HTML/Howto/Use_data_attributes +--- +<div>{{LearnSidebar}}</div> + +<p><a href="/en-US/docs/Web/Guide/HTML/HTML5" title="/en-US/docs/Web/Guide/HTML/HTML5">HTML5</a> 특정 요소와 연관되어 있지만 확정된 의미는 갖지 않는 데이터에 대한 확장 가능성을 염두에 두고 디자인되었습니다. <a href="/en-US/docs/Web/HTML/Global_attributes#attr-dataset"><code>data-*</code> 속성</a>은 표준이 아닌 속성이나 추가적인 DOM 속성, {{domxref("Node.setUserData()")}}과 같은 다른 조작을 하지 않고도, 의미론적 표준 HTML 요소에 추가 정보를 저장할 수 있도록 해줍니다.</p> + +<h2 id="HTML_문법">HTML 문법</h2> + +<p>문법은 간단합니다. 어느 엘리멘트에나 <code>data-</code>로 시작하는 속성은 무엇이든 사용할 수 있습니다. 화면에 안 보이게 글이나 추가 정보를 엘리멘트에 담아 놓을 수 있어요. 아래 <code>data</code> 사용법이 있습니다:</p> + +<pre class="brush: html"><article + id="electriccars" + data-columns="3" + data-index-number="12314" + data-parent="cars"> +... +</article></pre> + +<h2 id="JavaScript_에서_접근하기">JavaScript 에서 접근하기</h2> + +<p><a href="/en-US/docs/Web/JavaScript" title="/en-US/docs/Web/JavaScript">JavaScript</a> 에서 이 속성 값들을 읽는 방법은 너무 간단합니다. 값을 읽기 위한 완전한 HTML 이름과 함께 {{domxref("Element.getAttribute", "getAttribute()")}} 를 사용하면 됩니다. 그러나 표준은 더 간단한 방법을 정의합니다.: {{domxref("DOMStringMap")}} 는 {{domxref("HTMLElement.dataset", "dataset")}} 속성을 통해 읽어낼 수 있습니다.</p> + +<p><code>dataset</code> 객체를 통해 <code>data</code> 속성을 가져오기 위해서는 속성 이름의 <code>data-</code> 뒷 부분을 사용합니다.(대시들은 camelCase로 변환되는 것에 주의하세요.) </p> + +<pre class="brush: js">var article = document.getElementById('electriccars'); + +article.dataset.columns // "3" +article.dataset.indexNumber // "12314" +article.dataset.parent // "cars"</pre> + +<p>각 속성은 문자열이며 읽거나 쓸 수 있습니다. 위의 경우에서 <code>article.dataset.columns = 5</code>와 같이 설정하면 해당 속성을 <code>"5"</code>로 변경할 것입니다.</p> + +<h2 id="CSS_에서_접근하기">CSS 에서 접근하기</h2> + +<p>데이터 속성은 순 HTML 속성이기 때문에 <a href="/en-US/docs/Web/CSS" title="/en-US/docs/Web/CSS">CSS</a>에서도 접근할 수 있다는 것에 주목하세요. 예를 들어, 부모 데이터를 article에서 보여주려면 {{cssxref("attr")}} 함수의 <a href="/en-US/docs/Web/CSS/content" title="/en-US/docs/Web/CSS/content">생성된 content</a> 를 사용하면 됩니다.:</p> + +<pre class="brush: css">article::before { + content: attr(data-parent); +}</pre> + +<p>CSS의 <a href="/en-US/docs/Web/CSS/Attribute_selectors" title="/en-US/docs/Web/CSS/Attribute_selectors">속성 선택자</a>도 데이터에 따라 스타일을 바꾸는데 사용할 수 있습니다.:</p> + +<pre class="brush: css">article[data-columns='3'] { + width: 400px; +} +article[data-columns='4'] { + width: 600px; +}</pre> + +<p><a href="http://jsbin.com/ujiday/2/edit">이 JSBin 예시</a>에서 이들이 함께 작동하는 것을 볼 수 있습니다. </p> + +<p>데이터 속성들은 게임 점수와 같이 계속 변하는 정보도 저장할 수 있습니다. CSS선택자와 자바스크립트 접근을 이용해서 display 규칙을 사용하지 않고도 훌륭한 효과를 만들 수도 있습니다. 생성된 content와 CSS transition의 예시를 보려면 <a href="http://www.youtube.com/watch?v=On_WyUB1gOk">이 screencast</a> 를 확인하세요. (<a href="http://jsbin.com/atawaz/3/edit">JSBin 예시</a>).</p> + +<p><span style="line-height: 16.7999992370605px;">데이터 값은 문자열입니다. 스타일을 적용하려면 숫자 값은 선택자에 따옴표 안에 써주어야 합니다.</span></p> + +<h2 id="문제점">문제점</h2> + +<p>보여야 하고 접근 가능해야하는 내용은 데이터 속성에 저장하지 마세요. 접근 보조 기술이 접근할 수 없기 때문입니다. 또한 검색 크롤러가 데이터 속성의 값을 찾지 못할 것입니다.</p> + +<p>고려해야할 주요한 문제는 인터넷 익스플로러의 지원과 성능입니다. 인터넷 익스플로러11+ 은 표준을 지원하지만, 이전 버전들은 <a href="http://caniuse.com/#feat=dataset"><code>dataset</code>을 지원하지 않습니다</a>. IE 10 이하를 지원하기 위해서는 대신 {{domxref("Element.getAttribute", "getAttribute()")}}를 통해 데이터 속성을 접근해야 합니다. 또한, JS 데이터 저장소에 저장하는 것과 비교해서 <a href="http://jsperf.com/data-dataset">데이터 속성 읽기의 성능</a>은 저조합니다.</p> + +<p>하지만 이 때문에, 커스텀 요소와 관련된 메타 데이터를 위해서는 훌륭한 해결책입니다.</p> + +<p>Firefox 49.0.2(아마도 이전/이후의 버전)에서는,1022 데이터를 초과하는 데이터 속성은 자바스크립트(EcmaScript 4)가 읽지 못할 것입니다.</p> + +<h2 id="더_알아보기">더 알아보기</h2> + +<ul> + <li>This article is adapted from <a href="https://hacks.mozilla.org/2012/10/using-data-attributes-in-javascript-and-css/" title="https://hacks.mozilla.org/2012/10/using-data-attributes-in-javascript-and-css/">Using data attributes in JavaScript and CSS on hacks.mozilla.org</a>.</li> + <li>Custom attributes are also supported in SVG 2; see {{domxref("SVGElement.dataset")}} and {{SVGAttr("data-*")}} for more information.</li> + <li><a href="http://www.sitepoint.com/use-html5-data-attributes/">How to use HTML5 data attributes</a> (Sitepoint)</li> +</ul> diff --git a/files/ko/learn/html/index.html b/files/ko/learn/html/index.html new file mode 100644 index 0000000000..11776aba33 --- /dev/null +++ b/files/ko/learn/html/index.html @@ -0,0 +1,53 @@ +--- +title: HTML +slug: Learn/HTML +tags: + - Beginner + - HTML + - 입문자 +translation_of: Learn/HTML +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">웹사이트를 만들기 위해서는 웹 페이지 구조 정의의 토대가 되는 기술인 {{Glossary('HTML')}}에 대해 알아야 합나다. HTML은 작성하고자 하는 웹 콘텐츠가 문단인지, 리스트인지, 헤드라인인지, 링크인지, 이미지인지, 멀티미디어 플레이어인지, 폼 요소인지 아니면 기타 사용 가능한 다른 요소들 중의 하나인지, 혹은 새롭게 정의한 요소인지를 명확하기 인지할 수 있도록 하는데 사용됩니다.</p> + +<h2 id="학습_방향">학습 방향</h2> + +<p>HTML을 배우면서 시작하는 것이 가장 이상적입니다. <a href="/ko/docs/Learn/HTML/Introduction_to_HTML">HTML에 대한 소개</a>를 읽는 것부터 시작하세요. 그러면, 아래와 같은 고급 주제에 대해 배울 수 있게 될 것입니다. </p> + +<ul> + <li><a href="/ko/docs/Learn/CSS">CSS</a>, 그리고 HTML에 스타일을 적용하는 방법 (예를 들어, 사용된 텍스트 크기나 폰트를 변경하고, 테두리 선, 그림자 효과를 추가하고, 페이지의 레이아웃을 다단으로 편집하고, 애니메이션이나 다른 시각적인 효과를 추가할 수 있습니다.)</li> + <li><a href="/ko/docs/Learn/JavaScript">JavaScript</a>, 그리고 웹 페이지에 동적인 기능을 추가하는 방법 (예를 들어, 현재 위치를 찾아 지도 위에 표시하고, 버튼을 누를 때 마다 UI 요소를 노출하거나 숨길 수 있고, 사용자의 데이터를 로컬 시스템에 저장하는 것 등의 방법을 알 수 있습니다.)</li> +</ul> + +<p>이 주제를 학습하기에 앞서, 최소한 콘텐츠를 보면서 웹서핑하는 정도의 기초적인 컴퓨터 사용에 익숙해야 합니다. <a href="/ko/docs/Learn/Getting_started_with_the_web/기본_소프트웨어_설치하기">기본적인 소프트웨어를 설치</a>하여 작업환경의 기초를 설정하고, <a href="/ko/docs/Learn/Getting_started_with_the_web/파일들_다루기">파일을 다뤄보면서</a> 파일을 생성하고 관리하는 방법을 이해해야 합니다. 이 두 가지가 모두 초보자가 <a href="/ko/docs/Learn/Getting_started_with_the_web">웹을 정복하기 위한 기본</a>이 됩니다.</p> + +<p>이 주제를 공부하기 전에 <a href="/ko/docs/Learn/Getting_started_with_the_web">웹에 대한 기본 학습</a>을 추천하지만, 필수는 아닙니다. <a href="/ko/docs/Learn/Getting_started_with_the_web/HTML_기본">HTML의 기본</a>에서 다루는 대부분의 내용이 우리가 배우게 될 <a href="/ko/docs/Learn/HTML/Introduction_to_HTML">HTML 소개</a>에도 포함되어 있기는 하지만 좀 더 자세하게 다루고 있습니다.</p> + +<h2 id="구성">구성</h2> + +<p>이 주제는 각 단계를 통해 배울 수 있도록 미리 마련해 둔 아래와 같은 순서로 구성되어 있습니다. 첫 단계부터 순서대로 진행하길 바랍니다.</p> + +<dl> + <dt><a href="/ko/docs/Learn/HTML/Introduction_to_HTML">HTML 소개</a></dt> + <dd>이 과정은 중요한 컨셉과 구문을 배우게 되는 단계로 텍스트에 HTML을 적용하고, 파이퍼 링크를 추가하는 방법, HTML을 이용하여 웹 페이지의 구조를 작성하는 방법을 알아봅니다.</dd> + <dt><a href="/ko/docs/Learn/HTML/Multimedia_and_embedding">멀티미디어 요소 추가하기(embedding)</a></dt> + <dd>이 과정은 웹페이지에 HTML을 이용하여 멀티미디어 요소를 추가하는 방법, 이미지를 추가할 수 있는 다른 방법들, 그리고 비디오, 오디오, 혹은 다른 웹페이지를 삽입하는 방법을 살펴봅니다.</dd> + <dt><a href="/ko/docs/Learn/HTML/Forms">HTML 폼 요소</a></dt> + <dd>폼 요소는 웹에서 굉장히 중요합니다. 폼 요소는 회원가입, 로그인, 피드백 보내기, 물건 구입과 같이 웹사이트와 상호작용하는데 필요한 굉장히 많은 기능을 제공합니다. 이 과정은 폼 요소의 클라이언트 측 요소를 만드는 것으로 시작됩니다.</dd> + <dt>테이블(TBD)</dt> + <dd>웹페이지에 표 형태의 데이터를 이해 가능하고, {{glossary("Accessibility", "접근")}}할 수 있는 방법으로 표현하는 것은 도전이 될 수 있습니다. 이 과정은 좀 더 세부적인 기능인 캡션(caption)과 요약(summary)를 적용하는 방법과 함께 테이블 마크업의 기본을 다룹니다.</dd> +</dl> + +<h2 id="일반적인_HTML_문제_해결하기">일반적인 HTML 문제 해결하기</h2> + +<p>타이틀 다루기, 이미지, 비디오 강조된 콘텐츠, 기본 폼 요소 만들기 등 웹페이지를 만들때 생기는 <a href="/ko/docs/Learn/HTML/Howto">일반적인 문제들을 해결하기 위해 HTML을 이용</a>하는 방법을 설명하고 있는 콘텐츠 링크를 제공합니다.</p> + +<h2 id="함께_보기">함께 보기</h2> + +<div class="document-head" id="wiki-document-head"> +<dl> + <dt><a href="/ko/docs/Web/HTML">MDN HTML (HyperText Markup Language)</a></dt> + <dd>요소와 속성에 대한 상세한 설명을 담고 있는 MDN의 HTML 문서를 참고하는 것은 좋은 출발점입니다. 요소가 어떤 속성을 가지고 있는지, 어떤 값과 속성을 사용할 수 있는지를 알고 싶다면, 큰 도움이 될 것입니다.</dd> +</dl> +</div> diff --git a/files/ko/learn/html/introduction_to_html/advanced_text_formatting/index.html b/files/ko/learn/html/introduction_to_html/advanced_text_formatting/index.html new file mode 100644 index 0000000000..3bf2b758d7 --- /dev/null +++ b/files/ko/learn/html/introduction_to_html/advanced_text_formatting/index.html @@ -0,0 +1,478 @@ +--- +title: Advanced text formatting +slug: Learn/HTML/Introduction_to_HTML/Advanced_text_formatting +translation_of: Learn/HTML/Introduction_to_HTML/Advanced_text_formatting +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/Creating_hyperlinks", "Learn/HTML/Introduction_to_HTML/Document_and_website_structure", "Learn/HTML/Introduction_to_HTML")}}</div> + +<p class="summary">텍스트 서식에 있어서 <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals">HTML text fundamentals</a> 에서 이야기 하지 않은 수많은 요소들이 있습니다. 이 글에서 설명하는 요소들은 비교적 많이 알려져 있지않지만 여전히 유용합니다. (그리고 이것은 완전한 목록이 아닙니다.). 이 글에서 여러분은 인용구, 서술문, 컴퓨터 코드 및 관력 텍스트, 첨자, 위첨자, 연락처 정보 등을 표시하는 방법에 대해 알아봅시다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">요구 기술:</th> + <td><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Getting_started">Getting started with HTML</a> 에 설명된 기본적인 HTML 숙련도. <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals">HTML text fundamentals</a> 에서 설명하는 텍스트 포맷팅에 대한 지식.</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td> + <p>비교적 알려지지 않은 HTML 요소들을 사용하여 고급 시맨틱 기능을 사용하여 HTML을 구성하는 방법을 학습합니다.</p> + </td> + </tr> + </tbody> +</table> + +<h2 id="Description_lists">Description lists</h2> + +<p><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals">HTML text fundamentals</a> 에서 <a href="/en-US/Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals#Lists">mark up basic lists</a> 를 볼 수 있습니다. 하지만 해당 글에는 여러분이 앞으로 종종 마주할 세 번째 리스트 타입인 <strong>description lists</strong>에 대해선 언급하지 않았습니다. 이 리스트의 목적은 용어 및 정의, 질문 및 답변과 같은 일련의 항목 및 관련 설명을 표시하는 것입니다. 아래의 예시를 살펴봅시다.</p> + +<pre class="notranslate">soliloquy +In drama, where a character speaks to themselves, representing their inner thoughts or feelings and in the process relaying them to the audience (but not to other characters.) +monologue +In drama, where a character speaks their thoughts out loud to share them with the audience and any other characters present. +aside +In drama, where a character shares a comment only with the audience for humorous or dramatic effect. This is usually a feeling, thought or piece of additional background information</pre> + +<p>Description lists 는 다른 타입의 리스트와 다르게 {{htmlelement("dl")}} 태그를 사용합니다. 용어, 질문과 같은 상위 항목은 {{htmlelement("dt")}} (description term) 요소를 사용하고,\ 정의, 답변과 같은 하위 항목은 {{htmlelement("dd")}} (description definition) 요소를 사용합니다. 이해를 돕기위해 아래의 마크업 예시가 준비되어 있습니다.</p> + +<pre class="brush: html notranslate"><dl> + <dt>soliloquy</dt> + <dd>In drama, where a character speaks to themselves, representing their inner thoughts or feelings and in the process relaying them to the audience (but not to other characters.)</dd> + <dt>monologue</dt> + <dd>In drama, where a character speaks their thoughts out loud to share them with the audience and any other characters present.</dd> + <dt>aside</dt> + <dd>In drama, where a character shares a comment only with the audience for humorous or dramatic effect. This is usually a feeling, thought or piece of additional background information.</dd> +</dl></pre> + +<p>브라우저에서 제공하는 기본 스타일에 의해서 정의, 답변과 같은 하위 항목에 대해서 들여쓰기가 적용됩니다. 현재 보고계시는 description list 는 MDN에서 제공하는 스타일이 적용되어 있습니다. 이는 브라우저에서 제공하는 기본 스타일과 매우 유사하게 정의 되어 있습니다만, 추가적으로 정의된 스타일입니다.</p> + +<dl> + <dt>soliloquy</dt> + <dd>In drama, where a character speaks to themselves, representing their inner thoughts or feelings and in the process relaying them to the audience (but not to other characters.)</dd> + <dt>monologue</dt> + <dd>In drama, where a character speaks their thoughts out loud to share them with the audience and any other characters present.</dd> + <dt>aside</dt> + <dd>In drama, where a character shares a comment only with the audience for humorous or dramatic effect. This is usually a feeling, thought or piece of additional background information.</dd> + <dt></dt> +</dl> + +<p>아래의 예시와 같이 하나의 <code><dt></code> 에는 여러개의 <code><dd></code> 가 존재할 수 있습니다. </p> + +<pre class="notranslate"><dl> + <dt>aside</dt> + <dd>In drama, where a character shares a comment only with the audience for humorous or dramatic effect. This is usually a feeling, thought, or piece of additional background information.</dd> + <dd>In writing, a section of content that is related to the current topic, but doesn't fit directly into the main flow of content so is presented nearby (often in a box off to the side.)</dd> +</dl></pre> + +<dl> + <dt>aside</dt> + <dd>In drama, where a character shares a comment only with the audience for humorous or dramatic effect. This is usually a feeling, thought or piece of additional background information.</dd> + <dd>In writing, a section of content that is related to the current topic, but doesn't fit directly into the main flow of content so is presented nearby (often in a box off to the side.)</dd> + <dt></dt> +</dl> + +<h3 id="추가학습_일련의_정의_표시">추가학습: 일련의 정의 표시</h3> + +<p>description list 를 직접 시도해볼 시간입니다. input 필드에 요소들을 추가하여 output 필드에 description list 로 표시되도록 하십시오. 원하시는 경우에 추가적인 요소들을 추가하셔도 좋습니다.</p> + +<p>실수를 하셨을 경우에는, <em>Reset </em>버튼을 통해서 재시작하실 수 있습니다. 해답을 찾지 못하셨을 경우에 <em>Show solution</em> 버튼을 통해서 해답을 보실 수 있습니다.</p> + +<div class="hidden"> +<h6 id="Playable_code">Playable code</h6> + +<pre class="brush: html notranslate"><h2>Input</h2> +<textarea id="code" class="input">Bacon +The glue that binds the world together. +Eggs +The glue that binds the cake together. +Coffee +The drink that gets the world running in the morning. +A light brown color.</textarea> +<h2>Output</h2> +<div class="output"></div> +<div class="controls"> + <input id="reset" type="button" value="Reset" /> + <input id="solution" type="button" value="Show solution" /> +</div> +</pre> + +<pre class="brush: css notranslate">body { + font-family: 'Open Sans Light',Helvetica,Arial,sans-serif; +} + +.input, .output { + width: 90%; + height: 10em; + padding: 10px; + border: 1px solid #0095dd; + overflow: auto; +} + +button { + padding: 10px 10px 10px 0; +} +</pre> + +<pre class="brush: js notranslate">var textarea = document.getElementById("code"); +var reset = document.getElementById("reset"); +var code = textarea.value; +var output = document.querySelector(".output"); +var solution = document.getElementById("solution"); + +function drawOutput() { + output.innerHTML = textarea.value; +} + +reset.addEventListener("click", function() { + textarea.value = code; + drawOutput(); +}); + +solution.addEventListener("click", function() { +textarea.value = '<dl>\n <dt>Bacon</dt>\n <dd>The glue that binds the world together.</dd>\n <dt>Eggs</dt>\n <dd>The glue that binds the cake together.</dd>\n <dt>Coffee</dt>\n <dd>The drink that gets the world running in the morning.</dd>\n <dd>A light brown color.</dd>\n</dl>'; + drawOutput(); +}); + +textarea.addEventListener("input", drawOutput); +window.addEventListener("load", drawOutput); +</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code', 700, 500) }}</p> + +<h2 id="인용구">인용구</h2> + +<p>HTML에는 인용구 표시에 사용할 수 있는 요소가 존재합니다. 해당 요소는 블록 또는 인라인 요소인지에 따라서 다르게 표시됩니다.</p> + +<h3 id="Blockquotes">Blockquotes</h3> + +<p>블록 레벨 컨텐츠의 섹션(문단, 여러 단락, 리스트등)이 인용된 경우, 이를 나타내는 <code><blockquote></code>요소로 감싸야합니다. 그리고 <code>cite</code> 속성에 출처를 표기합니다. 아래의 예시는 MDN <code><blockquote></code> 요소 페이지를 인용한 것 입니다.</p> + +<pre class="brush: html notranslate"><p>The <strong>HTML <code>&lt;blockquote&gt;</code> Element</strong> (or <em>HTML Block +Quotation Element</em>) indicates that the enclosed text is an extended quotation.</p></pre> + +<p>이것을 block quote 로 변경하기 위해서 아래와 같이 할 수 있습니다.</p> + +<pre class="brush: html notranslate"><blockquote cite="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/blockquote"> + <p>The <strong>HTML <code>&lt;blockquote&gt;</code> Element</strong> (or <em>HTML Block + Quotation Element</em>) indicates that the enclosed text is an extended quotation.</p> +</blockquote></pre> + +<p>브라우저 기본 스타일은 인용구를 표현할 때, 들여쓰기 된 단락으로 나타냅니다. MDN은 추가적인 스타일링과 함께 이를 나타냅니다.</p> + +<blockquote cite="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/blockquote"> +<p>The <strong>HTML <code><blockquote></code> Element</strong> (or <em>HTML Block Quotation Element</em>) indicates that the enclosed text is an extended quotation.</p> +</blockquote> + +<h3 id="Inline_quotations">Inline quotations</h3> + +<p>인라인 인용구는 <code><q></code> 요소를 사용한다는 점만 제외하면 블럭 인용구와 동일하게 동작합니다. 아래의 마크업 예시는 MDN <code><q></code> 페이지의 인용문을 포함합니다.</p> + +<pre class="brush: html notranslate"><p>The quote element — <code>&lt;q&gt;</code> — is <q cite="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/q">intended +for short quotations that don't require paragraph breaks.</q></p></pre> + +<p>브라우저 기본 스타일은 인라인 인용구를 따옴표로 묶은 일반 텍스트로 표현합니다.</p> + +<p>The quote element — <code><q></code> — is <q cite="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/q">intended for short quotations that don't require paragraph breaks.</q></p> + +<h3 id="Citations">Citations</h3> + +<p>{{htmlattrxref("cite","blockquote")}}요소의 컨텐츠는 유용하게 보이지만 안타깝게도 브라우저, 스크린 리더 등은 이를 이용해서 할 수 있는 것이 많지 않습니다. 브라우저는 javascript나 CSS로 여러분이 직접 해결책을 제시하지 않는다면 <code>cite</code> 컨텐츠를 화면에 표시할 방법이 없습니다. 페이지에서 인용 출처를 화면에 나타나게 하고 싶다면 <code><cite></code> 요소를 사용하는 것이 더 좋습니다. 이는 이름 그대로 출처를 포함하기 위해서 사용됩니다. — <code><cite></code> 요소 안에 있는 출처에 대한 링크를 연결할 수 있습니다.</p> + +<pre class="brush: html notranslate"><p>According to the <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/blockquote"> +<cite>MDN blockquote page</cite></a>: +</p> + +<blockquote cite="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/blockquote"> + <p>The <strong>HTML <code>&lt;blockquote&gt;</code> Element</strong> (or <em>HTML Block + Quotation Element</em>) indicates that the enclosed text is an extended quotation.</p> +</blockquote> + +<p>The quote element — <code>&lt;q&gt;</code> — is <q cite="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/q">intended +for short quotations that don't require paragraph breaks.</q> -- <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/q"> +<cite>MDN q page</cite></a>.</p></pre> + +<p>Citations are styled in italic font by default. You can see this code at work in our <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/advanced-text-formatting/quotations.html">quotations.html</a> example.</p> + +<h3 id="추가학습_누가_말했어">추가학습: 누가 말했어?</h3> + +<p>다른 실습 과제를 할 시간입니다! 이번 예제에서는 아래 항목을 수행하고자 합니다.</p> + +<ol> + <li>중간에 위치한 문단을 <code>cite</code> 속성을 지닌 블럭 인용구로 변경하십시오.</li> + <li>세 번째 문단의 일부를 <code>cite</code> 속성을 지닌 인라인 인용구로 변경하십시오.</li> + <li>각 링크에 <cite> 요소를 포함시키십시오.</li> +</ol> + +<p>적절한 출처를 찾기 위해서 온라인 검색을 이용하십시오.</p> + +<p>실수를 하셨을 경우에는, <em>Reset </em>버튼을 통해서 재시작하실 수 있습니다. 해답을 찾지 못하셨을 경우에 <em>Show solution</em> 버튼을 통해서 해답을 보실 수 있습니다.</p> + +<div class="hidden"> +<h6 id="Playable_code_2">Playable code</h6> + +<pre class="brush: html notranslate"><h2>Input</h2> +<textarea id="code" class="input"><p>Hello and welcome to my motivation page. As Confucius once said:</p> + +<p>It does not matter how slowly you go as long as you do not stop.</p> + +<p>I also love the concept of positive thinking, and The Need To Eliminate Negative Self Talk +(as mentioned in Affirmations for Positive Thinking.)</p></textarea> +<h2>Output</h2> +<div class="output"></div> +<div class="controls"> + <input id="reset" type="button" value="Reset" /> + <input id="solution" type="button" value="Show solution" /> +</div> +</pre> + +<pre class="brush: css notranslate">body { + font-family: 'Open Sans Light',Helvetica,Arial,sans-serif; +} + +.input, .output { + width: 90%; + height: 10em; + padding: 10px; + border: 1px solid #0095dd; + overflow: auto; +} + +button { + padding: 10px 10px 10px 0; +} +</pre> + +<pre class="brush: js notranslate">var textarea = document.getElementById("code"); +var reset = document.getElementById("reset"); +var code = textarea.value; +var output = document.querySelector(".output"); +var solution = document.getElementById("solution"); + +function drawOutput() { + output.innerHTML = textarea.value; +} + +reset.addEventListener("click", function() { + textarea.value = code; + drawOutput(); +}); + +solution.addEventListener("click", function() { +textarea.value = '<p>Hello and welcome to my motivation page. As <a href="http://www.brainyquote.com/quotes/authors/c/confucius.html"><cite>Confucius</cite></a> once said:</p>\n\n<blockquote cite="http://www.brainyquote.com/quotes/authors/c/confucius.html">\n <p>It does not matter how slowly you go as long as you do not stop.</p>\n</blockquote>\n\n<p>I also love the concept of positive thinking, and <q cite="http://www.affirmationsforpositivethinking.com/index.htm">The Need To Eliminate Negative Self Talk</q> (as mentioned in <a href="http://www.affirmationsforpositivethinking.com/index.htm"><cite>Affirmations for Positive Thinking</cite></a>.)</p>'; + drawOutput(); +}); + +textarea.addEventListener("input", drawOutput); +window.addEventListener("load", drawOutput); +</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code_2', 700, 500) }}</p> + +<h2 id="약어">약어</h2> + +<p>웹을 둘러 볼 때 <code><abbr></code> 요소를 꽤 많이 볼 수 있습니다. 이는 머리 글자 또는 약어를 나타내는데 사용됩니다. title 속성을 통해 원래의 용어를 나태날 수 있습니다. 몇가지 예제를 살펴 보겠습니다.</p> + +<pre class="notranslate"><p>We use <abbr title="Hypertext Markup Language">HTML</abbr> to structure our web documents.</p> + +<p>I think <abbr title="Reverend">Rev.</abbr> Green did it in the kitchen with the chainsaw.</p></pre> + +<p>위의 코드는 아래와 같이 보입니다. 용어의 전체 뜻은 마우스를 올려 놓으면 툴팁에 표시됩니다.</p> + +<p>We use <abbr title="Hypertext Markup Language">HTML</abbr> to structure our web documents.</p> + +<p>I think <abbr title="Reverend">Rev.</abbr> Green did it in the kitchen with the chainsaw.</p> + +<div class="note"> +<p><strong>Note</strong>: 약어를 나타내기 위해 <abbr> 과 동일하게 사용할 수 있는 <code><acronym></code> 가 존재합니다. 이는 사용중지 되었으며 브라우저에서도 호환되지 않는 경우가 있습니다. 따라서 <code><abbr></code> 을 대신 사용하는 것을 추천드립니다.</p> +</div> + +<h3 id="추가학습_약어_만들기">추가학습: 약어 만들기</h3> + +<p>아래의 간단한 실습 과제를 통해 약어 사용에 대한 학습을 하고자 합니다. 아래의 샘플을 그대로 사용하시거나 여러분의 샘플로 교체 하실 수 있습니다. </p> + +<div class="hidden"> +<h6 id="Playable_code_3">Playable code</h6> + +<pre class="brush: html notranslate"><h2>Input</h2> +<textarea id="code" class="input"><p>NASA sure does some exciting work.</p></textarea> +<h2>Output</h2> +<div class="output"></div> +<div class="controls"> + <input id="reset" type="button" value="Reset" /> + <input id="solution" type="button" value="Show solution" /> +</div> +</pre> + +<pre class="brush: css notranslate">body { + font-family: 'Open Sans Light',Helvetica,Arial,sans-serif; +} + +.input, .output { + width: 90%; + height: 5em; + padding: 10px; + border: 1px solid #0095dd; + overflow: auto; +} + +button { + padding: 10px 10px 10px 0; +} +</pre> + +<pre class="brush: js notranslate">var textarea = document.getElementById("code"); +var reset = document.getElementById("reset"); +var code = textarea.value; +var output = document.querySelector(".output"); +var solution = document.getElementById("solution"); + +function drawOutput() { + output.innerHTML = textarea.value; +} + +reset.addEventListener("click", function() { + textarea.value = code; + drawOutput(); +}); + +solution.addEventListener("click", function() { +textarea.value = '<p><abbr title="National Aeronautics and Space Administration">NASA</abbr> sure does some exciting work.</p>'; + drawOutput(); +}); + +textarea.addEventListener("input", drawOutput); +window.addEventListener("load", drawOutput); +</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code_3', 700, 350) }}</p> + +<h2 id="연락처_세부_사항_표시">연락처 세부 사항 표시</h2> + +<p>HTML 에서 <code><address></code> 태그를 이용해서 연락처 세부 정보를 표시할 수 있습니다. 이것은 단순히 연락처 정보를 표시하는 것입니다.</p> + +<pre class="brush: html notranslate"><address> + <p>Chris Mills, Manchester, The Grim North, UK</p> +</address></pre> + +<p>그러나 기억해야 할 것은 <address> 요소는 HTML 문서를 작성한 사람의 연락처 정보를 표시하기 위해서 사용되어야 한다는 것입니다. 따라서 Chris 가 마크 업이 표시된 문서를 작성한 경우에만 위의 예제가 정상입니다. 아래와 같은 예제도 괜찮습니다.</p> + +<pre class="brush: html notranslate"><address> + <p>Page written by <a href="../authors/chris-mills/">Chris Mills</a>.</p> +</address></pre> + +<h2 id="위첨자와_아래_첨자">위첨자와 아래 첨자</h2> + +<p>여러분은 종종 날짜, 화학 공식 및 수학 방적식과 같은 항목을 표시 할 때 올바른 의미를 갖도록 위첨자 아래 첨자를 사용해야 할 수도 있습니다. <code><sup></code> 과 <code><sub></code> 요소들은 이를 위해 사용할 수 있습니다.</p> + +<pre class="brush: html notranslate"><p>My birthday is on the 25<sup>th</sup> of May 2001.</p> +<p>Caffeine's chemical formula is C<sub>8</sub>H<sub>10</sub>N<sub>4</sub>O<sub>2</sub>.</p> +<p>If x<sup>2</sup> is 9, x must equal 3 or -3.</p></pre> + +<p>표시될 결과는 아래와 같습니다.</p> + +<p>My birthday is on the 25<sup>th</sup> of May 2001.</p> + +<p>Caffeine's chemical formula is C<sub>8</sub>H<sub>10</sub>N<sub>4</sub>O<sub>2</sub>.</p> + +<p>If x<sup>2</sup> is 9, x must equal 3 or -3.</p> + +<h2 id="컴퓨터_코드를_나타내기">컴퓨터 코드를 나타내기</h2> + +<p>HTML 을 이용해 컴퓨터 코드를 나타낼 때 아래와 같은 많은 요소들을 사용할 수 있습니다.</p> + +<ul> + <li>{{htmlelement("code")}}: 일반적인 컴퓨터 코드를 표시합니다.</li> + <li>{{htmlelement("pre")}}: 공백(일반적으로 코드 블록)을 유지하기 위해 사용합니다. 택스트 내에서 들여 쓰기 또는 초과 공백을 사용하면 브라우저가 이를 무시하고 렌더링 된 페이지에 공백을 표시하지 않습니다. 그러나 <code><pre></pre></code> 태그로 텍스트를 감싸면 공백이 텍스트 편집기에서 보는 것과 동일하게 렌더링 됩니다.</li> + <li>{{htmlelement("var")}}: 변수이름을 특별하게 표시합니다.</li> + <li>{{htmlelement("kbd")}}: 컴퓨터에 입력 된 키보드 (및 기타 유형) 입력을 표시합니다.</li> + <li>{{htmlelement("samp")}}: 컴퓨터 프로그램의 출력을 표시합니다.</li> +</ul> + +<p>몇 가지 예를 살펴 보겠습니다. 이 예제들을 통해서 자유롭게 학습해보십시오. (다른 <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/advanced-text-formatting/other-semantics.html">other-semantics.html</a> 샘플 파일의 사본을 사용하실 수 있습니다).</p> + +<pre class="brush: html notranslate"><pre><code>var para = document.querySelector('p'); + +para.onclick = function() { + alert('Owww, stop poking me!'); +}</code></pre> + +<p>You shouldn't use presentational elements like <code>&lt;font&gt;</code> and <code>&lt;center&gt;</code>.</p> + +<p>In the above JavaScript example, <var>para</var> represents a paragraph element.</p> + + +<p>Select all the text with <kbd>Ctrl</kbd>/<kbd>Cmd</kbd> + <kbd>A</kbd>.</p> + +<pre>$ <kbd>ping mozilla.org</kbd> +<samp>PING mozilla.org (63.245.215.20): 56 data bytes +64 bytes from 63.245.215.20: icmp_seq=0 ttl=40 time=158.233 ms</samp></pre></pre> + +<p>위의 코드는 아래와 같이 표시됩니다.</p> + +<p>{{ EmbedLiveSample('Representing_computer_code','100%',300, "", "", "hide-codepen-jsfiddle") }}</p> + +<h2 id="시간과_날짜_표시">시간과 날짜 표시</h2> + +<p>HTML 은 기계가 읽을 수 있는 형식(machine-readable)으로 시간과 날짜를 표시하기 위한 <code><time></code> 요소를 제공합니다. 예를 들면 아래와 같습니다.</p> + +<pre class="brush: html notranslate"><<span class="pl-ent">time</span> <span class="pl-e">datetime</span>=<span class="pl-s"><span class="pl-pds">"</span>2016-01-20<span class="pl-pds">"</span></span>>20 January 2016</<span class="pl-ent">time</span>></pre> + +<p>이것이 왜 유용할까요? 인간이 날짜를 기록하는 방법에는 여러 가지가 있습니다. 위 날짜는 아래와 같이 나타낼 수 있습니다.</p> + +<ul> + <li>20 January 2016</li> + <li>20th January 2016</li> + <li>Jan 20 2016</li> + <li>20/06/16</li> + <li>06/20/16</li> + <li>The 20th of next month</li> + <li><span lang="fr">20e Janvier 2016</span></li> + <li><span lang="ja">2016年1月20日</span></li> + <li>And so on</li> +</ul> + +<p>그러나 이러한 다른 형식들은 컴퓨터가 쉽게 인식할 수 없습니다. 페이지의 모든 이벤트 날짜를 자동으로 인식하여 캘린더에 삽입하려면 어떻게 해야합니까? <code><time></code> 요소를 사용하면 기계가 읽을 수 있는 명확한 시간 / 날짜를 첨부 할 수 있습니다.</p> + +<p>아래의 기본 예지는 간단한 기계 판독 가능 날짜를 제공하지만 사용 가능한 다른 많은 옵션들이 존재합니다.</p> + +<pre class="brush: html notranslate"><!-- Standard simple date --> +<<span class="pl-ent">time</span> <span class="pl-e">datetime</span>=<span class="pl-s"><span class="pl-pds">"</span>2016-01-20<span class="pl-pds">"</span></span>>20 January 2016</<span class="pl-ent">time</span>> +<!-- Just year and month --> +<<span class="pl-ent">time</span> <span class="pl-e">datetime</span>=<span class="pl-s"><span class="pl-pds">"</span>2016-01<span class="pl-pds">"</span></span>>January 2016</<span class="pl-ent">time</span>> +<!-- Just month and day --> +<<span class="pl-ent">time</span> <span class="pl-e">datetime</span>=<span class="pl-s"><span class="pl-pds">"</span>01-20<span class="pl-pds">"</span></span>>20 January</<span class="pl-ent">time</span>> +<!-- Just time, hours and minutes --> +<<span class="pl-ent">time</span> <span class="pl-e">datetime</span>=<span class="pl-s"><span class="pl-pds">"</span>19:30<span class="pl-pds">"</span></span>>19:30</<span class="pl-ent">time</span>> +<!-- You can do seconds and milliseconds too! --> +<<span class="pl-ent">time</span> <span class="pl-e">datetime</span>=<span class="pl-s"><span class="pl-pds">"</span></span>19:30:01.856<span class="pl-s"><span class="pl-pds">"</span></span>>19:30:01.856</<span class="pl-ent">time</span>> +<!-- Date and time --> +<<span class="pl-ent">time</span> <span class="pl-e">datetime</span>=<span class="pl-s"><span class="pl-pds">"</span>2016-01-20T19:30<span class="pl-pds">"</span></span>>7.30pm, 20 January 2016</<span class="pl-ent">time</span>> +<!-- Date and time with timezone offset--> +<<span class="pl-ent">time</span> <span class="pl-e">datetime</span>=<span class="pl-s"><span class="pl-pds">"</span>2016-01-20T19:30<span class="pl-pds">+01:00"</span></span>>7.30pm, 20 January 2016 is 8.30pm in France</<span class="pl-ent">time</span>> +<!-- Calling out a specific week number--> +<<span class="pl-ent">time</span> <span class="pl-e">datetime</span>=<span class="pl-s"><span class="pl-pds">"</span>2016-W04<span class="pl-pds">"</span></span>>The fourth week of 2016</<span class="pl-ent">time</span>></pre> + +<h2 id="요약">요약</h2> + +<p>HTML 텍스트 시맨틱에 대한 스터디가 끝났습니다. 이 과정에서 학습한 내용이 HTML 텍스트 요소의 전부가 아님을 명심하십시오. 우리는 필수 요소를 위주로 다루고 싶었고, 여러분이 일반적인 상황에서 보거나 적어도 흥미롭게 다가올 수 있는 더 일반적인 것들 중 일부를 다루려고 했습니다. 더 많은 HTML 요소를 찾으려면 <a href="/en-US/docs/Web/HTML/Element">HTML element reference</a> 를 살펴보십시오.(<a href="/en-US/docs/Web/HTML/Element#Inline_text_semantics">Inline text semantics</a> 섹션은 시작하기에 좋은 장소입니다.). 다음 문서에서는 HTML 문서의 다른 부분을 구성하는 데 사용할 HTML 요소를 살펴 보겠습니다.</p> + +<p>{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/Creating_hyperlinks", "Learn/HTML/Introduction_to_HTML/Document_and_website_structure", "Learn/HTML/Introduction_to_HTML")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Getting_started">Getting started with HTML</a></li> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML">What’s in the head? Metadata in HTML</a></li> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals">HTML text fundamentals</a></li> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Creating_hyperlinks">Creating hyperlinks</a></li> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Advanced_text_formatting">Advanced text formatting</a></li> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Document_and_website_structure">Document and website structure</a></li> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Debugging_HTML">Debugging HTML</a></li> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Marking_up_a_letter">Marking up a letter</a></li> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Structuring_a_page_of_content">Structuring a page of content</a></li> +</ul> diff --git a/files/ko/learn/html/introduction_to_html/creating_hyperlinks/index.html b/files/ko/learn/html/introduction_to_html/creating_hyperlinks/index.html new file mode 100644 index 0000000000..73619df1cf --- /dev/null +++ b/files/ko/learn/html/introduction_to_html/creating_hyperlinks/index.html @@ -0,0 +1,338 @@ +--- +title: 하이퍼링크 만들기 +slug: Learn/HTML/Introduction_to_HTML/Creating_hyperlinks +tags: + - a태그 + - 웹하이퍼링크 + - 하이퍼링크 +translation_of: Learn/HTML/Introduction_to_HTML/Creating_hyperlinks +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals", "Learn/HTML/Introduction_to_HTML/Advanced_text_formatting", "Learn/HTML/Introduction_to_HTML")}}</div> + +<p class="summary">하이퍼 링크는 중요하다. — 웹을 웹답게 만들기 때문이다. 이 글에서는 링크를 만드는데 필요한 구문을 보여주고 링크의 모범 사례를 설명한다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">미리 알아두면 좋은 지식들:</th> + <td>기본적인 HTML 에 대한 친숙함, as covered in <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Getting_started">Getting started with HTML</a>. HTML text formatting, as covered in <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals">HTML text fundamentals</a>.</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td> + <p>하이퍼링크를 효과적으로 다루는 방법과 수많은 파일들을 함께 연결하는 방법을 배웁니다.</p> + </td> + </tr> + </tbody> +</table> + +<h2 id="하이퍼링크란_무엇인가">하이퍼링크란 무엇인가?</h2> + +<p>하이퍼링크는 웹이 제공하는 가장 흥미로운 혁신 중 하나입니다, 하이퍼링크는 웹이 시작된 이래 웹의 특성이었습니다. 그러나 하이퍼링크는 웹을 웹 다워보이도록 만들어줍니다. — 문서들을 다른 문서들과 연결시켜 주기도 하구요. 또는 우리가 원하는 다른 resource 들과 연결해주기도 합니다. 우리는 또한 문서들의 특정 부분들끼리 연결할 수 있죠.그리고 우리는 앱들을 단순한 웹 주소를 통해 이용하게 만들 수도 있습니다. (설치 혹은 여러가지 작업들을 필요로 하는 native 앱과 비교해보세요.) 거의 모든 web content 들은 링크로 바뀔 수 있는데요. 우리가 그것들을 클릭하거나 활성화시키면 웹 브라우저가 다른 웹 주소({{glossary("URL")}})로 갑니다. </p> + +<div class="note"> +<p><strong>메모</strong>: URL은 HTML 파일, 텍스트 파일, 이미지, 텍스트 문서들, 비디오와 오디오 파일들, 그리고 웹상에서 존재할 수 있는 어느 것이라 할지라도 연결할 수 있다.만약 웹 브라우저가 어떻게 파일을 보여주거나 다룰지 모른다면, 웹 브라우저는 당신이 파일을 열기를 원하는지 (만약 그렇다면, 파일을 열거나 처리하는 것에 대한 의무는 device에서 적절한 native 앱에게 넘겨질 겁니다.) 혹은 파일을 다운로드 하기를 원하는지 (만약 그렇다면, 당신은 그것을 나중에 다룰 수 있습니다.) 궁금해 할 것입니다.</p> +</div> + +<p>예를 들면, BBC 홈페이지엔 많은 링크들이 있는데요. 그것들은 수많은 뉴스들 뿐만 아니라 다른 웹사이트들 (navigation functionality), 로그인/등록 페이지들 (user tools) 그리고 더 많은 다른 곳에도 연결되어 있습니다.</p> + +<p><img alt="frontpage of bbc.co.uk, showing many news items, and navigation menu functionality" src="https://mdn.mozillademos.org/files/12405/bbc-homepage.png" style="display: block; margin: 0 auto;"></p> + +<h2 id="링크의_구조">링크의 구조</h2> + +<p>A basic link is created by wrapping the text (or other content, see {{anch("Block level links")}}) you want to turn into a link inside an {{htmlelement("a")}} element, and giving it an {{htmlattrxref("href", "a")}} 속성은 (also known as a <strong>target</strong>) 사이트의 주소가 포함된 링크를 당신에게 줍니다.</p> + +<pre class="brush: html"><p>I'm creating a link to +<a href="https://www.mozilla.org/en-US/">the Mozilla homepage</a>. +</p></pre> + +<p>위 코드의 결과는 다음과 같습니다:</p> + +<p>나는 링크를 만들었다. <a class="ignore-external" href="https://www.mozilla.org/en-US/">the Mozilla homepage</a>. </p> + +<h3 id="title_속성에_부가적인_정보를_더하기">title 속성에 부가적인 정보를 더하기</h3> + +<p><code>title</code>; 속성은 해당 페이지에 어떤 종류의 정보가 포함되어 있는지 또는 알아야할 사항과 같은 링크에 대한 보충할만한 유용한 정보를 포함하기 위한 것을 나타낼때 사용한다.</p> + +<p>예제 코드 :</p> + +<pre class="brush: html"><p>I'm creating a link to +<a href="https://www.mozilla.org/en-US/" + title="The best place to find more information about Mozilla's + mission and how to contribute">the Mozilla homepage</a>. +</p></pre> + +<p>이것은 그리고 마우스를 오버했을때에 툴팁에 대한 기능도 제공해줄 수 있다.</p> + +<p>제가 만든 링크 입니다. <a class="ignore-external" href="https://www.mozilla.org/en-US/" title="The best place to find more information about Mozilla's mission and how to contribute">the Mozilla homepage</a>.</p> + +<div class="note"> +<p><strong>Note</strong>: 링크 제목은 마우스 호버시에만 공개 된다. 이것은 웹 페이지를 탐색하기 위해 키보드에만 의존하는 사람들이 타이틀 정보에 접근하는데 어려움을 겪게 된다는 것을 의미한다. 만약 title의 정보가 페이지 사용에 있어서 정말로 중요하다면, 해당하는 정보를 일반 텍스트에 넣어줌으로써 모든 사용자가 접근할 수 있는 방식으로 제시해주어야한다.</p> +</div> + +<h3 id="능동학습_링크를_만들어봅시다.">능동학습: 링크를 만들어봅시다.</h3> + +<p>적극적으로 학습해 봅시다: local code 편집기를 사용해서 하나의 HTML document 를 만드세요. (<a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/getting-started/index.html">소스코드: 템플릿 시작하기</a>가 잘 될거에요.)</p> + +<ul> + <li>HTML body 속에, 하나의 혹은 더 많은 paragraph 들, 혹은 당신이 이미 알고 있는 다른 타입의 content 들을 더해보세요.</li> + <li>몇몇의 content들을 링크로 바꾸세요.</li> + <li>타이틀 속성들을 더하세요.</li> +</ul> + +<h3 id="Block_level_링크들">Block level 링크들</h3> + +<p>이전에 얘기했듯이, 여러분은 어떤 내용이든 link로 바꿀 수 있습니다. <a href="https://developer.mozilla.org/en-US/Learn/HTML/Introduction_to_HTML/Getting_started#Block_versus_inline_elements">block level 요소들</a> 이라고 할지라도요. 만약 링크로 바꾸고 싶은 이미지가 있다면, <code><a> 와 </a></code> 사이에 그 이미지를 넣으시기만 하시면 됩니다.</p> + +<pre class="brush: html"><a href="https://www.mozilla.org/en-US/"> + <img src="mozilla-image.png" alt="mozilla logo that links to the mozilla homepage"> +</a></pre> + +<div class="note"> +<p><strong>메모</strong>: 나중에 보실 글에선 웹에서 이미지를 사용하는 것에 대해 더 많이 배우실 겁니다.</p> +</div> + +<h2 id="URL_과_path_에_대한_기본_지침">URL 과 path 에 대한 기본 지침</h2> + +<p> link target 에 대해 완전히 이해하기 위해서, URL 과 파일 path에 대하여 이해하실 필요가 있습니다. 이번 시간에는 여러분께서 성취하실 필요가 있는 정보에 대해서 알려드릴게요.</p> + +<p>URL, 혹은 Uniform Resource Locator 은 단순히 무언가가 웹상의 어디에 위치하는지 결정하는 하나의 텍스트 문자열이랍니다. 예를 들면, Mozilla's 영어 홈페이지는<code>https://www.mozilla.org/en-US/</code>이죠.</p> + +<p>URL은 파일들을 찾기위해 path를 이용합니다. path는 당신이 관심있어 하는 파일이 파일 시스템 어디에 있는지 구체적으로 명시하구요. 디렉토리 구조에 대한 예제를 보시죠. (see the <a href="https://github.com/mdn/learning-area/tree/master/html/introduction-to-html/creating-hyperlinks">creating-hyperlinks</a> directory.)</p> + +<p><img alt="A simple directory structure. The parent directory is called creating-hyperlinks and contains two files called index.html and contacts.html, and two directories called projects and pdfs, which contain an index.html and a project-brief.pdf file, respectively" src="https://mdn.mozillademos.org/files/12409/simple-directory.png" style="display: block; margin: 0 auto;"></p> + +<p>이 디렉토리 구조의 <strong>root</strong>는 <code>creating-hyperlinks</code>. 웹사이트를 로컬 단에서 다룰 때에는 전체 웹사이트가 모두 들어갈 수 있는 하나의 디렉토리를 가져야 할 것입니다. Root 안에서 우리는 <code>index.html</code> 파일과 <code>contacts.html </code>파일을 갖습니다. 진짜 웹사이트 안에서 <code>index.html</code> 는 우리의 홈 페이지 또는 랜딩 페이지(웹사이트의 접속 포인트 또는 웹사이트의 특정 부분 이 되는 페이지)가 될 것입니다. </p> + +<p>또 Root 안에는 두 개의 디렉토리가 있습니다 — <code>pdfs</code> 와 <code>projects</code>. 이들은 각각 하나의 파일을 내부에 가지고 있습니다 — 각각 PDF (<code>project-brief.pdf</code>) 와 <code>index.html</code> 파일입니다. 당신은 두 개의 <code>index.html</code> 파일들을 각각 파일 시스템의 다른 위치에 있도록 해서 하나의 프로젝트 안에 가질 수 있습니다. 많은 웹 사이트들이 이렇게 하고 있습니다. 두번째 <code>index.html</code>는 아마 프로젝트와 관련된 정보의 메인 랜딩 페이지가 될 것입니다.</p> + +<ul> + <li> + <p><strong>같은 디렉토리(폴더)</strong>: <code>contacts.html</code>을 가리키는 하이퍼링크를 <code>index.html</code>(top level <code>index.html</code>) 안에 포함시키려면 현재 파일과 동일한 디렉토리에 연결하려는 파일의 파일 이름만 지정하면 된다. 따라서 사용할 URL은 <code>contacts.html</code>: 입니다.</p> + </li> +</ul> + +<pre class="brush: html"><p>Want to contact a specific staff member? +Find details on our <a href="contacts.html">contacts page</a>.</p></pre> + +<ul> + <li> + <p><strong>하위 디렉토리로 하향 이동</strong>: <code>projects/index.html</code>을 가리키는 하이퍼링크를 internal <code>index.html</code>(<code>index.html</code>에 상위 레벨)에 포함시키려면 연결하려는 파일을 표시하기 전에 프로젝트 디렉토리로 내려가야 할 것이다. 이 작업은 디렉토리 이름, 그 다음 슬래시, 그 다음 파일 이름을 지정하여 수행되므로 사용할 URL은<code>projects/index.html</code> 입니다.</p> + </li> +</ul> + +<pre class="brush: html"><p>Visit my <a href="projects/index.html">project homepage</a>.</p></pre> + +<ul> + <li><strong>부모 디렉토리로 상향 이동</strong>: <code>pdfs/project-brief.pdf</code>를 가리키는 하이퍼링크를 <code>projects/index.html</code> 안에 포함시키려면 디렉토리 레벨을 올린 다음 pdf 디렉토리로 다시 내려가야 할 것이다. "상위 디렉터리 이동"은 두 개의 점을 사용하여 표시된다. — <code>..</code> — 따라서 사용할 URL은 <code>../pdfs/project-brief.pdf</code>:</li> +</ul> + +<pre class="brush: html"><p>A link to my <a href="../pdfs/project-brief.pdf">project brief</a>.</p></pre> + +<div class="note"> +<p><strong>Note</strong>: 필요한 경우 아래와 같이 이러한 기능의 여러 인스턴스를 복잡한 URL로 결합할 수 있다 <code>../../../complex/path/to/my/file.html</code>.</p> +</div> + +<h3 id="Document_fragments문서_조각">Document fragments(문서 조각)</h3> + +<p>문서 상단이 아닌 HTML 문서 내부의 특정 부분(Document fragments(문서 조각)에 링크 할 수 있다. 그것을 하기 위해서 먼저 당신은 링크를 시키고 싶은 태그에 {{htmlattrxref("id")}} 속성을 넣어 주어야한다. 일반적으로는 특정 헤드라인에 연결하는 것이 타당하다.</p> + +<p>예제:</p> + +<pre class="brush: html"><h2 id="Mailing_address">Mailing address</h2></pre> + +<p>만약 특정 ID에 연결하려면 URL 끝에 해시/파운드 기호를 포함하면 된다,</p> + +<p>예제:</p> + +<pre class="brush: html"><p>Want to write us a letter? Use our <a href="contacts.html#Mailing_address">mailing address</a>.</p></pre> + +<p>Document fragments(문서 조각)를 단독으로 사용하여 동일한 문서의 다른 부분에 연결할 수 있다</p> + +<pre class="brush: html"><p>The <a href="#Mailing_address">company mailing address</a> can be found at the bottom of this page.</p></pre> + +<h3 id="절대_URL과_상대_URL">절대 URL과 상대 URL</h3> + +<p>웹에서는 절대 URL과 상대 URL 두 가지의 용어를 찾아볼 수 있습니다.</p> + +<p><strong>절대 URL</strong>: 웹에서 정의된 상대적인 위치를 가리킵니다. {{glossary("protocol")}} and {{glossary("domain name")}} 포함. 예를 들어, 만약 <code>index.html</code> 페이지가 <code>projects</code> 폴더에 업로드 되면 이는 웹 서버의 root 안에 위치하게 되고 <br> + 웹 사이트 도메인은 <code>http://www.example.com</code>,<br> + 그 페이지는 <code>http://www.example.com/projects/index.html</code><br> + (혹은 그저 <code>http://www.example.com/projects/</code>, 대부분의 웹 서버는 URL에서 명시되지 않은 경우 페이지를 불러오기 위해 <code>index.html</code> 과 같은 랜딩 페이지를 찾습니다.)</p> + +<p>절대 URL은 어디에 사용되든 항상 같은 장소를 가리킵니다.</p> + +<p><strong>상대 URL</strong>: 당신이 link하고 있는 파일(과거 섹션의 파일 같은)로부터 상대적인 위치를 가리킵니다. 예를 들어, 우리가 예시 파일 <code>http://www.example.com/projects/index.html</code> 에서 같은 디렉토리에 있는 PDF 파일로 link하고 싶다면, URL은 <code>project-brief.pdf</code> 과 같이 파일이름이어야 할 것입니다— 추가 정보는 필요 없습니다. 만약 PDF 파일이 <code>projects</code> 하위 디렉토리인 <code>pdfs</code>에 있다면, 상대 URL은 <code>pdfs/project-brief.pdf</code> 일 것입니다. (같은 URL로 <code>http://www.example.com/projects/pdfs/project-brief.pdf</code>.)</p> + +<p>상대 URL은 파일의 실제 위치가 어디냐에 따라 다른 장소를 가리킬 것입니다. — 예를 들어 우리가 <code>index.html</code> 파일을 <code>projects</code> 디렉토리에서 웹사이트의 root로 옮긴다면 (최상위, 어느 디렉토리에도 포함되지 않음), <code>pdfs/project-brief.pdf</code> 의 상대 URL은 <code>http://www.example.com/pdfs/project-brief.pdf</code>를 가리킬 것입니다. <br> + <code>http://www.example.com/projects/pdfs/project-brief.pdf</code>를 가리키지 않습니다.</p> + +<p>물론, 당신이 <code>index.html</code> 파일을 옮겼다고 해서 <code>project-brief.pdf</code> 파일과 <code>pdfs</code> 폴더의 위치가 갑자기 바뀌지는 않을 것입니다- 이것은 당신의 링크가 잘못된 곳을 가리키게 할 것이므로 클릭을 해도 제대로 작동하지 않을 것입니다. 주의하세요!</p> + +<h2 id="Link_실습하기">Link 실습하기</h2> + +<p>링크 작성시 지켜야할 몇가지 모범 사례에 대해 살펴보자</p> + +<ul> +</ul> + +<h3 id="링크_명을_명확하게">링크 명을 명확하게</h3> + +<p>당신의 페이지에 링크를 올리는 것은 쉽다. 그것으로는 충분하지 않다. 우리는 모든 독자들에게 현재 상황과 그들이 선호하는 도구에 상관없이 접근성 높은 우리의 링크를 만들 필요가 있다.</p> + +<p>예를 들면:</p> + +<ul> + <li>스크린리더 사용자들은 링크에서 페이지 링크를 넘고, 컨텍스트에서 벗어난 링크를 읽는 것을 좋아한다.</li> + <li>검색 엔진은 링크 텍스트를 사용하여 대상 파일을 인덱싱하므로 링크 텍스트에 키워드를 포함시켜 링크되는 내용을 효과적으로 설명하는 것이 좋다.</li> + <li>시각적 독자들은 한 마디 한 마디를 읽기보다는 페이지를 훑어보고, 그들의 눈에는 링크처럼 눈에 띄는 페이지 특징이 그려질 것이다. 그들은 링크 텍스트가 유용하다는 것을 알게 될 것이다.</li> +</ul> + +<p>구체적인 예제를 한번 살펴보자:</p> + +<p><em> link test:</em> <a href="https://firefox.com">Download Firefox</a></p> + +<pre class="brush: html"><p><a href="https://firefox.com/"> + Download Firefox +</a></p></pre> + +<p><em><strong>Bad</strong> link text:</em> <a href="https://firefox.com/">Click here</a> to download Firefox</p> + +<pre class="brush: html"><p><a href="https://firefox.com/"> + Click here +</a> +to download Firefox</p> +</pre> + +<p>Other tips:</p> + +<ul> + <li>링크 텍스트의 일부로 URL을 작성하지마세요 — URL은 보기 흉하며, 화면 판독기가 글자로 URL을 읽어낼 때 이상하게 들린다.</li> + <li>링크 텍스트에 "link"나 "links to"라고 쓰지마라 — 그것은 단지 소음이다. Screen readers 사용자들은 사용자에게 연관성이 있다고 말한다. 링크에는 일반적으로 다른 색상으로 스타일링 되고 밑줄이 그어져 있기 때문에 시각적으로 브라우저를 보는 사람들도 링크가 있다는 것을 알기 때문이다. (사용자들이 일반적으로 익숙하기 때문에 이 관습은 깨지면 안된다.)</li> + <li>링크 라벨은 가능한 짧게 유지하자 — 긴 링크는 특히 전체 내용을 읽어야하는 screen reader 사용자들을 짜증나게 한다.</li> + <li>동일한 텍스트의 여러 복사본이 서로 다른 위치에 연결되는 인스턴스 최소화. 이것은 스크린리더 사용자들에게 문제를 일으킬 수 있는데, 그들은 종종 문맥에서 링크 목록을 꺼낸다. "여기를 클릭", "여기를 클릭", "여기를 클릭"이라고 표시된 모든 링크를 여러 개 제시한다. 혼란스러울 것이다.</li> +</ul> + +<h3 id="가능하면_상대_링크_사용하기">가능하면 상대 링크 사용하기</h3> + +<p>위의 설명에서, 당신은 절대 링크를 항상 사용하는 것이 좋은 생각이라고 생각할 수 있다; 결국, 그것들은 페이지가 상대적인 링크처럼 움직였을 때 깨지지 않는다. 그러나 동일한 웹 사이트 내의 다른 위치에 연결할 때 가능한 한 상대 링크를 사용해야 한다(다른 웹 사이트에 연결할 때는 절대 링크를 사용해야 한다).</p> + +<ul> + <li>우선, 당신의 코드를 스캔하는 것이 훨씬 쉽다. — 상대 링크가 일반적으로 절대 링크보다 훨씬 짧기 때문에 코드를 읽는 것이 훨씬 더 쉽다.</li> + <li>둘째, 가능한 한 상대적인 URL을 이용하는 것이 더 효율적이다. 절대 URL을 사용할 때, 브라우저는 {{glossary("DNS")}}로 도메인 이름을 쿼리하여 서버의 실제 위치를 조회하는 것으로 시작하고, 그 서버로 가서 요청되고 있는 파일을 찾는다. 반면에 상대적인 URL을 사용하면, 브라우저는 요청되고 있는 파일을 같은 서버에서 찾아 볼 뿐이다. 따라서 상대 URL이 할 수 있는 절대 URL을 사용하면 브라우저가 계속해서 추가 작업을 수행하도록 만들 수 있으며, 이것은 브라우저의 성능이 저하된다는 것을 의미한다.</li> +</ul> + +<h3 id="비_HTML_리소스_연결_시_-_명확한_표식_남기기"> 비 HTML 리소스 연결 시 - 명확한 표식 남기기</h3> + +<p>PDF나 워드 문서와 같이 다운로드되거나 스트리밍되거나(비디오나 오디오와 같은) 다른 예상하지 못한 효과(팝업 창을 열거나 플래시 동영상을 로드)에 연결할 때는 명확한 표현을 추가하여 혼란을 줄 수 있어야 한다. 그것은 꽤 성가실 수 있다.</p> + +<p>예를 들어:</p> + +<ul> + <li>대역폭이 낮은 연결에 있는 경우 링크를 클릭하면 멀티 메가바이트 다운로드가 예기치 않게 시작된다.</li> + <li>플래시 플레이어를 설치하지 않은 경우 링크를 클릭한 다음 플래시가 필요한 페이지로 이동한다.</li> +</ul> + +<p>여기서 사용할 수 있는 텍스트의 종류를 보려면 몇 가지 예를 살펴보십시오.:</p> + +<pre class="brush: html"><p><a href="http://www.example.com/large-report.pdf"> + Download the sales report (PDF, 10MB) +</a></p> + +<p><a href="http://www.example.com/video-stream/"> + Watch the video (stream opens in separate tab, HD quality) +</a></p> + +<p><a href="http://www.example.com/car-game"> + Play the car game (requires Flash) +</a></p></pre> + +<h3 id="다운로드_연결_시_download_attribute_사용">다운로드 연결 시 download attribute 사용</h3> + +<p>브라우저에서 열지 않고 다운로드할 리소스에 연결하는 경우 다운로드 속성을 사용하여 기본 저장 파일 이름을 제공할 수 있다.</p> + +<p>Firefox 39의 Windows 버전에 대한 다운로드 링크가 있는 예:</p> + +<pre class="brush: html"><a href="https://download.mozilla.org/?product=firefox-39.0-SSL&os=win&lang=en-US" + download="firefox-39-installer.exe"> + Download Firefox 39 for Windows +</a></pre> + +<h2 id="활동적인_학습_탐색_메뉴_만들기">활동적인 학습: 탐색 메뉴 만들기</h2> + +<p>이 연습에서는 일부 페이지를 탐색 메뉴와 함께 연결하여 다중 페이지 웹 사이트를 생성하십시오. 이것은 웹사이트가 만들어지는 하나의 일반적인 방식이다. — 동일한 탐색 메뉴를 포함한 모든 페이지에 동일한 페이지 구조가 사용되기 때문에 링크를 클릭할 때 같은 장소에 머물고 있다는 인상을 주며, 다른 내용이 제기되고 있다.</p> + +<p>다음 4개의 페이지의 로컬 복사본을 서로 동일한 디렉토리에 만들어야 한다 (전체 목록을 보려면 <a href="https://github.com/mdn/learning-area/tree/master/html/introduction-to-html/navigation-menu-start">navigation-menu-start</a> 디렉토리를 참조):</p> + +<ul> + <li><a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/navigation-menu-start/index.html">index.html</a></li> + <li><a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/navigation-menu-start/projects.html">projects.html</a></li> + <li><a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/navigation-menu-start/pictures.html">pictures.html</a></li> + <li><a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/navigation-menu-start/social.html">social.html</a></li> +</ul> + +<p>당신이 해야할 것:</p> + +<ol> + <li>연결할 페이지의 이름이 포함된 순서 없는 목록을 한 페이지의 지정된 위치에 추가하십시오. 네비게이션 메뉴는 보통 링크의 목록일 뿐이므로 의미적으로 OK이다.</li> + <li>각 페이지 이름을 해당 페이지 링크로 변경하십시오.</li> + <li>Navigation 메뉴를 각 페이지에 복사하십시오.</li> + <li>각 페이지에서 동일한 페이지에 대한 링크만 제거하십시오. — 페이지에 대한 링크가 포함된다는 것은 혼란스럽고 의미가 없으며, 링크가 부족하면 현재 어떤 페이지에 있는지 시각적으로 잘 알 수 있다.</li> +</ol> + +<p>완성된 예는 다음과 같다:</p> + +<p><img alt="An example of a simple HTML navigation menu, with home, pictures, projects, and social menu items" src="https://mdn.mozillademos.org/files/12411/navigation-example.png" style="display: block; margin: 0 auto;"></p> + +<div class="note"> +<p><strong>Note</strong>: 만약 당신이 막히거나, 당신이 그것을 제대로 가지고 있는지 확신할 수 없다면, 당신은 정확한 답을 보기 위해 <a href="https://github.com/mdn/learning-area/tree/master/html/introduction-to-html/navigation-menu-marked-up">navigation-menu-marked-up</a> 디렉토리를 확인할 수 있다.</p> +</div> + +<h2 id="이메일_링크">이메일 링크</h2> + +<p>클릭했을 때 리소스나 페이지에 연결하지 않고 새 발신 전자 메일 메시지를 여는 링크나 단추를 만들 수 있다.</p> + +<p>이것은 {{HTMLElement("a")}} 태그안에 <code>mailto:</code> URL 스키마를 사용하여 구현할 수 있다.</p> + +<p>가장 기본적이고 일반적으로 사용되는 형태의 <code>mailto:</code> 링크는 단순히 대상 수신인의 이메일 주소를 표시한다.</p> + +<p>예를 들면:</p> + +<pre class="brush: html"><a href="mailto:nowhere@mozilla.org">Send email to nowhere</a> +</pre> + +<p>이렇게 되면 다음과 같은 링크가 생성된다: <a href="mailto:nowhere@mozilla.org">Send email to nowhere</a>.</p> + +<p>사실, 이메일 주소는 심지어 선택사항이다. 그것을 생략하면(즉, 당신의 {{htmlattrxref("href", "a")}} 아직 목적지 주소가 지정되지 않은 사용자의 메일 클라이언트에 의해 새로운 발신 이메일 창이 열린다. 이것은 종종 사용자가 선택한 주소로 이메일을 보내기 위해 클릭할 수 있는 "공유" 링크로서 유용하다.</p> + +<h3 id="세부_사항_지정하기">세부 사항 지정하기</h3> + +<p>이메일 주소 외에도 다른 정보를 제공할 수 있다. 실제로 표준 메일 헤더 필드는 사용자가 제공하는 <code>mailto</code> URL에 추가할 수 있다. 이것들 중 가장 일반적으로 사용되는 것은 "subject", "cc", and "body"(참된 헤더 필드는 아니지만 새 이메일에 대한 짧은 내용 메시지를 지정할 수 있음)이다. 각 필드와 그 값은 조회 용어로 지정된다.</p> + +<p>아래 예제가 cc, bcc, subject and body 를 포함한다.:</p> + +<pre class="brush: html"><a href="mailto:nowhere@mozilla.org?cc=name2@rapidtables.com&bcc=name3@rapidtables.com&amp;subject=The%20subject%20of%20the%20email &amp;body=The%20body%20of%20the%20email"> + Send mail with cc, bcc, subject and body +</a></pre> + +<div class="note"> +<p><strong>Note:</strong> 각 필드의 값은 URL로 인코딩되어야 한다(즉, 출력되지 않은 문자 및 <a href="http://en.wikipedia.org/wiki/Percent-encoding">percent-escaped</a>). 또한 <code>mailto: </code>URL의 각 필드를 구분하는 <code>&</code> 의 사용에 유의하십시오. 이것은 표준 URL 쿼리 표기법입니다.</p> +</div> + +<p>여기 다른 몇 가지 <code>mailto</code> URL 샘플들이 있다:</p> + +<ul> + <li><a href="mailto:">mailto:</a></li> + <li><a href="mailto:nowhere@mozilla.org">mailto:nowhere@mozilla.org</a></li> + <li><a href="mailto:nowhere@mozilla.org,nobody@mozilla.org">mailto:nowhere@mozilla.org,nobody@mozilla.org</a></li> + <li><a href="mailto:nowhere@mozilla.org?cc=nobody@mozilla.org">mailto:nowhere@mozilla.org?cc=nobody@mozilla.org</a></li> + <li><a href="mailto:nowhere@mozilla.org?cc=nobody@mozilla.org&subject=This%20is%20the%20subject">mailto:nowhere@mozilla.org?cc=nobody@mozilla.org&subject=This%20is%20the%20subject</a></li> +</ul> + +<h2 id="요약">요약</h2> + +<p>이제 링크는 여기까지입니다, 어쨌든! 나중에 스타일링을 시작하면 링크로 돌아간다. 다음 HTML에서는 텍스트 의미론(Text Semantics)으로 돌아가서 유용하게 사용할 수 있는 고급/비정상적인 기능을 살펴보도록 하겠다. — 다음 목적지는 고급 텍스트 서식에 대해 알아볼 것이다.</p> + +<p>{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals", "Learn/HTML/Introduction_to_HTML/Advanced_text_formatting", "Learn/HTML/Introduction_to_HTML")}}</p> diff --git a/files/ko/learn/html/introduction_to_html/debugging_html/index.html b/files/ko/learn/html/introduction_to_html/debugging_html/index.html new file mode 100644 index 0000000000..6b359dce5c --- /dev/null +++ b/files/ko/learn/html/introduction_to_html/debugging_html/index.html @@ -0,0 +1,179 @@ +--- +title: HTML 디버깅 +slug: Learn/HTML/Introduction_to_HTML/Debugging_HTML +translation_of: Learn/HTML/Introduction_to_HTML/Debugging_HTML +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/Document_and_website_structure", "Learn/HTML/Introduction_to_HTML/Marking_up_a_letter", "Learn/HTML/Introduction_to_HTML")}}</div> + +<p class="summary">HTML을 작성을 할 수 있지만, 문제가 생겼을 때 코드의 오류가 발생한 부분을 해결할 수 없나요? 이 기사에서는 HTML의 오류를 찾고 수정하는 데 도움이되는 몇 가지 도구를 소개합니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">선행사항:</th> + <td>HTML이 익숙해야 합니다. 다음문서를 이해하는 정도면 충분합니다. <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Getting_started">HTML로 시작하기</a>, <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals">HTML 텍스트 기본사항</a>, and <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Creating_hyperlinks">하이파링크 만들기</a>.</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>HTMl에서 문제를 찾기위해 디버깅 툴을 사용하는 기본적인 방법을 배웁니다.</td> + </tr> + </tbody> +</table> + +<h2 id="디버깅은_무섭지_않아요.">디버깅은 무섭지 않아요.</h2> + +<p>여러분이 원하든 원하지않든 무언가 잘못되면 코드가 동작하지 않거나 검파일 애러가 나는 무시무시한 순간이 다가옵니다. 다음과 같이 말이죠</p> + +<p>아래는 <a href="https://www.rust-lang.org/">Rust</a> 언어로 작성된 간단한 프로그램을 {{glossary ( "compile")}}할 때 발생한 오류를 보여줍니다.</p> + +<p><img alt="A console window showing the result of trying to compile a rust program with a missing quote around a string in a print statement. The error message reported is error: unterminated double quote string." src="https://mdn.mozillademos.org/files/12435/error-message.png" style="display: block; height: 520px; margin: 0px auto; width: 711px;"></p> + +<p>여기나온 오류 메시지는 상대적으로 이해하기 쉽습니다. "끝나지 않은 큰 따옴표 문자열". 애러 내용을 보면 코드 2번째 줄의 <code>println! (Hello, world! ");</code>에 큰 따옴표가 누락 된 것을 금방 볼 수 있습니다. 하지만 프로그램이 커질수록 오류 메시지는 점점더 복잡해지고 해석하기가 쉽지 않아집니다. 단순한 경우라 할지라도 Rust에 대해 전혀 모르는 사람에게 약간 무섭게 보일 수 있습니다.(보통은 점점 무서워지죠..)</p> + +<p>그래도 디버깅을 무서워하지 않으셔도 됩니다! 프로그래밍 언어나 코드를 작성하고 디버깅하는 데 있어 중요한 것은 언어와 도구에 익숙해지는 것입니다. (익숙해져야 합니다!)</p> + +<h2 id="HTML과_디버깅">HTML과 디버깅</h2> + +<p>HTML은 Rust만큼 복잡하지 않습니다. HTML은 브라우저가 구문 분석하기 전에 다른 형식으로 컴파일되지 않으며 결과를 표시합니다 (해석되지 않고 컴파일되지 않음). 그리고 HTML의 {{glossary ( "element")}} 구문은 Rust, {{glossary ( "JavaScript")}} 또는 {{glossary ( "Python")}}과 같은 "실제 프로그래밍 언어"보다 이해하기 쉽습니다. 브라우저가 HTML을 구문 분석하는 방식은 프로그래밍 언어가 실행되는 방식보다 훨씬 유연(<strong>permissive</strong>)합니다. 이는 좋은 점이기도 하지만 나쁜 점이기도 합니다.</p> + +<h3 id="허용_코드">허용 코드</h3> + +<p>그렇다면 유연함(<strong>permissive</strong>)이란 무엇일까요? 음, 일반적으로 코드에서 뭔가 잘못했을 때, 두 가지 주요 유형의 오류가 발생합니다.</p> + +<ul> + <li><strong>문법 오류(Syntax errors)</strong>: 이러한 오류는 위에 표시된 Rust 오류와 같이 실제로 프로그램이 실행되지 않는 코드의 맞춤법 오류입니다. 이들은 일반적으로 언어 구문에 익숙하고 오류 메시지의 의미를 알고있다면 수정하기 쉽습니다.</li> + <li><strong>논리 에러(Logic errors)</strong>: 언어 문법이 올바르게 작성된 오류입니다. 동작은 하지만 코드가 의도한 것과 다르게 동작하므로 프로그램이 잘못 실행됩니다. 오류의 원인을 알려주는 오류 메시지가 없으므로 구문 오류보다 수정하기가 더 어렵습니다.</li> +</ul> + +<p>브라우저 자체에서 구문 분석을하기 때문에 HTML 자체는 문법 오류가 발생하지 않으므로 문법 오류가 있어도 페이지가 계속 표시됩니다. 브라우저에는 잘못 작성된 마크 업을 해석하는 방법을 설명하는 규칙이 내장되어 있으므로 여러분이 생각한대로 결과가 나오지 않더라도 HTML페이지가 표시됩니다. 물론 문제가 될 수 있습니다!</p> + +<div class="note"> +<p><strong>Note</strong>: 웹이 처음 만들어지면 사람들이 자신의 콘텐트를 게시 할 수 있도록 허용하는 것이 문법이 정확한지 확인하는 것보다 중요하기 때문에 HTML은 허용 된 방식으로 구문 분석됩니다. 처음부터 웹 사이트가 문법오류에 엄격했다면 웹은 오늘날처럼 인기가 있지 않았을 것입니다.</p> +</div> + +<h3 id="자발적_학습_Permissive한_코드를_배웁니다.">자발적 학습 : Permissive한 코드를 배웁니다.</h3> + +<p>유연한 성질의 HTML 코드를 배울 시간입니다.</p> + +<ol> + <li>첫째로, 우리의 <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/debugging-html/debug-example.html">debug-example demo</a>를 다운로드하고 Local에 저장하세요. This demo is deliberately written to have some errors in it for us to explore (the HTML markup is said to be <strong>badly-formed</strong>, as opposed to <strong>well-formed</strong>).</li> + <li>Next, open it in a browser. You will see something like this:<img alt="A simple HTML document with a title of HTML debugging examples, and some information about common HTML errors, such as unclosed elements, badly nested elements, and unclosed attributes. " src="https://mdn.mozillademos.org/files/12437/badly-formed-html.png" style="display: block; margin: 0 auto;"></li> + <li>This immediately doesn't look great; let's look at the source code to see if we can work out why (only the body contents are shown): + <pre class="brush: html notranslate"><h1>HTML debugging examples</h1> + +<p>What causes errors in HTML? + +<ul> + <li>Unclosed elements: If an element is <strong>not closed properly, + then its effect can spread to areas you didn't intend + + <li>Badly nested elements: Nesting elements properly is also very important + for code behaving correctly. <strong>strong <em>strong emphasised?</strong> + what is this?</em> + + <li>Unclosed attributes: Another common source of HTML problems. Let's + look at an example: <a href="https://www.mozilla.org/>link to Mozilla + homepage</a> +</ul></pre> + </li> + <li>Let's review the problems: + <ul> + <li>The {{htmlelement("p","paragraph")}} and {{htmlelement("li","list item")}} elements have no closing tags. Looking at the image above, this doesn't seem to have affected the markup rendering too badly, as it is easy to infer where one element should end and another should begin.</li> + <li>The first {{htmlelement("strong")}} element has no closing tag. This is a bit more problematic, as it isn't easy to tell where the element is supposed to end. In fact, the whole of the rest of the text has been strongly emphasised.</li> + <li>This section is badly nested: <code><strong>strong <em>strong emphasised?</strong> what is this?</em></code>. It is not easy to tell how this has been interpreted because of the previous problem.</li> + <li>The {{htmlattrxref("href","a")}} attribute value has a missing closing double quote. This seems to have caused the biggest problem — the link has not rendered at all.</li> + </ul> + </li> + <li>Now let's look at the markup the browser has rendered, as opposed to the markup in the source code. To do this, we can use the browser developer tools. If you are not familiar with how to use your browser's developer tools, take a few minutes to review <a href="/en-US/docs/Learn/Discover_browser_developer_tools">Discover browser developer tools</a>.</li> + <li>In the DOM inspector, you can see what the rendered markup looks like: <img alt="The HTML inspector in Firefox, with our example's paragraph highlighted, showing the text "What causes errors in HTML?" Here you can see that the paragraph element has been closed by the browser." src="https://mdn.mozillademos.org/files/12439/html-inspector.png" style="display: block; margin: 0 auto;"></li> + <li>Using the DOM inspector, let's explore our code in detail to see how the browser has tried to fix our HTML errors (we did the review in Firefox; other modern browsers <em>should</em> give the same result): + <ul> + <li>The paragraphs and list items have been given closing tags.</li> + <li>It isn't clear where the first <code><strong></code> element should be closed, so the browser has wrapped each separate block of text with its own strong tag, right down to the bottom of the document!</li> + <li>The incorrect nesting has been fixed by the browser like this: + <pre class="brush: html notranslate"><strong>strong + <em>strong emphasised?</em> +</strong> +<em> what is this?</em></pre> + </li> + <li>The link with the missing double quote has been deleted altogether. The last list item looks like this: + <pre class="brush: html notranslate"><li> + <strong>Unclosed attributes: Another common source of HTML problems. + Let's look at an example: </strong> +</li></pre> + </li> + </ul> + </li> +</ol> + +<h3 id="HTML_validation">HTML validation</h3> + +<p>So you can see from the above example that you really want to make sure your HTML is well-formed! But how? In a small example like the one seen above, it is easy to search through the lines and find the errors, but what about a huge, complex HTML document?</p> + +<p>The best strategy is to start by running your HTML page through the <a href="https://validator.w3.org/">Markup Validation Service</a> — created and maintained by the W3C, the organization that looks after the specifications that define HTML, CSS, and other web technologies. This webpage takes an HTML document as an input, goes through it, and gives you a report to tell you what is wrong with your HTML.</p> + +<p><img alt="The HTML validator homepage" src="https://mdn.mozillademos.org/files/12441/validator.png" style="display: block; margin: 0 auto;"></p> + +<p>To specify the HTML to validate, you can give it a web address, upload an HTML file, or directly input some HTML code.</p> + +<h3 id="Active_learning_Validating_an_HTML_document">Active learning: Validating an HTML document</h3> + +<p>Let's try this with our <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/debugging-html/debug-example.html">sample document</a>.</p> + +<ol> + <li>First, load up the <a href="https://validator.w3.org/">Markup Validation Service</a> in one browser tab, if it isn't already.</li> + <li>Switch to the <a href="https://validator.w3.org/#validate_by_input">Validate by Direct Input</a> tab.</li> + <li>Copy all the sample document's code (not just the body) and paste it into the large text area shown in the Markup Validation Service.</li> + <li>Press the <em>Check</em> button.</li> +</ol> + +<p>This should give you a list of errors and other information.</p> + +<p><img alt="A list of of HTML validation results from the W3C markup validation service" src="https://mdn.mozillademos.org/files/12443/validation-results.png" style="display: block; margin: 0 auto;"></p> + +<h4 id="Interpreting_the_error_messages">Interpreting the error messages</h4> + +<p>The error messages are usually helpful, but sometimes they are not so helpful; with a bit of practice you can work out how to interpret these to fix your code. Let's go through the error messages and what they mean. You'll see that each message comes with a line and column number to help you to locate the error easily.</p> + +<ul> + <li>"End tag <code>li</code> implied, but there were open elements" (2 instances): These messages indicate that an element is open that should be closed. The ending tag is implied, but not actually there. The line/column information points to the first line after the line where the closing tag should really be, but this is a good enough clue to see what is wrong.</li> + <li>"Unclosed element <code>strong</code>": This is really easy to understand — a {{htmlelement("strong")}} element is unclosed, and the line/column information points right to where it is.</li> + <li>"End tag <code>strong</code> violates nesting rules": This points out the incorrectly nested elements, and the line/column information points out where it is.</li> + <li>"End of file reached when inside an attribute value. Ignoring tag": This one is rather cryptic; it refers to the fact that there is an attribute value not properly formed somewhere, possibly near the end of the file because the end of the file appears inside the attribute value. The fact that the browser doesn't render the link should give us a good clue as to what element is at fault.</li> + <li>"End of file seen and there were open elements": This is a bit ambiguous, but basically refers to the fact there are open elements that need to be properly closed. The lines numbers point to the last few lines of the file, and this error message comes with a line of code that points out an example of an open element: + <pre class="notranslate">example: <a href="https://www.mozilla.org/>link to Mozilla homepage</a> ↩ </ul>↩ </body>↩</html></pre> + + <div class="note"> + <p><strong>Note</strong>: An attribute missing a closing quote can result in an open element because the rest of the document is interpreted as the attribute's content.</p> + </div> + </li> + <li>"Unclosed element <code>ul</code>": This is not very helpful, as the {{htmlelement("ul")}} element <em>is</em> closed correctly. This error comes up because the {{htmlelement("a")}} element is not closed, due to the missing closing quote mark.</li> +</ul> + +<p><span>If you can't work out what every error message means, don't worry about it — a good idea is to try fixing a few errors at a time. Then try revalidating your HTML to show what errors are left. Sometimes fixing an earlier error will also get rid of other error messages — several errors can often be caused by a single problem, in a domino effect.</span></p> + +<p><span>You will know when all your errors are fixed when you see the following banner in your output:</span></p> + +<p><img alt='Banner that reads "The document validates according to the specified schema(s) and to additional constraints checked by the validator."' src="https://mdn.mozillademos.org/files/12445/valid-html-banner.png" style="display: block; margin: 0 auto;"></p> + +<h2 id="요약">요약</h2> + +<p>그래서 HTML을 디버깅하는 방법에 대해 소개합니다. 이 방법은 나중에 CSS, JavaScript 및 다른 유형의 코드를 디버깅 할 때 유용한 기술을 제공합니다. 이것은 또한 HTML 모듈 학습 입문의 끝 부분입니다. 이제 평가를 통해 스스로 테스트 할 수 있습니다. 첫 번째 것은 아래에 링크되어 있습니다.</p> + +<p>{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/Document_and_website_structure", "Learn/HTML/Introduction_to_HTML/Marking_up_a_letter", "Learn/HTML/Introduction_to_HTML")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Getting_started">Getting started with HTML</a></li> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML">What’s in the head? Metadata in HTML</a></li> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals">HTML text fundamentals</a></li> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Creating_hyperlinks">Creating hyperlinks</a></li> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Advanced_text_formatting">Advanced text formatting</a></li> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Document_and_website_structure">Document and website structure</a></li> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Debugging_HTML">Debugging HTML</a></li> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Marking_up_a_letter">Marking up a letter</a></li> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Structuring_a_page_of_content">Structuring a page of content</a></li> +</ul> diff --git a/files/ko/learn/html/introduction_to_html/document_and_website_structure/index.html b/files/ko/learn/html/introduction_to_html/document_and_website_structure/index.html new file mode 100644 index 0000000000..868313807c --- /dev/null +++ b/files/ko/learn/html/introduction_to_html/document_and_website_structure/index.html @@ -0,0 +1,267 @@ +--- +title: Document and website structure +slug: Learn/HTML/Introduction_to_HTML/Document_and_website_structure +translation_of: Learn/HTML/Introduction_to_HTML/Document_and_website_structure +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/Advanced_text_formatting", "Learn/HTML/Introduction_to_HTML/Debugging_HTML", "Learn/HTML/Introduction_to_HTML")}}</div> + +<p class="summary">당신의 페이지의 (단락 또는 이미지 같은) 개개의 파트를 정의할 뿐 아니라, {{glossary("HTML")}}은 웹 사이트의 구역을 정의하는 ("헤더", "네비게이션 메뉴", "메인 컨텐츠 칼럼"과 같은) 수많은 블록 수준 요소들로 웹 사이트를 자랑합니다. 이번 글은 어떻게 기본 웹 구조를 설계하고, 어떻게 그 구조를 나타내는 HTML을 작성하는지 살펴봅니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">선행 조건:</th> + <td><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Getting_started">Getting started with HTML</a>의 HTML의 기본. <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals">HTML text fundamentals</a>의 HTML 텍스트 형식. <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Creating_hyperlinks">Creating hyperlinks</a>의 하이퍼링크의 동작 방식.</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>시멘틱 태그를 사용하여 문서 구조를 만드는 방법과 간단한 웹사이트 구조 만드는 방법을 배운다.</td> + </tr> + </tbody> +</table> + +<h2 id="문서의_기본_섹션">문서의 기본 섹션</h2> + +<p>웹페이지는 서로 많이 다르게 보일 수 있지만, 페이지가 전체화면 비디오 혹은 게임이거나 예술 프로젝트, 좋지 않은 구조를 가지고 있지 않은 이상에는 대부분 유사한 구성 요소를 가지고 있습니다.</p> + +<dl> + <dt>header</dt> + <dd>일반적으로 큰 제목과 로고 등이 있는 큰 띠. 한 웹페이지에서 주요 정보가 있는 곳입니다.</dd> + <dt>navigation bar</dt> + <dd>홈 페이지의 메인 섹션으로 연결합니다; 대부분 메뉴 버튼이나 링크, 탭으로 표현됩니다. 헤더와 같이, 이 항목은 대부분 한 페이지로부터 다른 페이지로 넘어가도 구성으로 남아있습니다. — 웹 사이트에서 일관적이지 못한 네비게이션을 사용할 경우 방문자는 복잡함과 불만족스러움을 느낄 것입니다. 많은 웹 디자이너들은 네비게이션 바를 개별적인 구성 요소로 사용하기 보다 hearder bar의 일부로 다루지만 이는 필수 사항은 아닙니다; 사실 일부 사람들은 접근성을 위해서는 두 개로 나누는 것이 좋다고 주장하는데, 나뉜 경우 스크린 리더들이 두 특징들을 더 잘 읽을 수 있기 때문입니다.</dd> + <dt>main content</dt> + <dd>웹 페이지에서 가장 독특한 컨텐츠를 포함하고 있는 중심의 큰 부분으로, 예를 들어, 당신이 보고 싶어하는 비디오, 당신이 읽고 있는 주요 이야기, 당신이 보고 싶어하는 지도, 또는 뉴스 헤드라인 등이 있습니다. 물론 이 부분은 각 페이지마다 다른 웹 사이트의 한 부분입니다. </dd> + <dt>sidebar</dt> + <dd>주변의 정보, 링크, 인용 부호, 광고 등입니다. 일반적으로 이는 메인 컨텐츠에 무엇이 포함되어 있느냐에 따라 다릅니다. (예를 들어 기사 페이지에서, sidebar는 작성자의 소개, 또는 관련 기사 링크를 포함할 것입니다.) 그러나 보조 navigation system으로서 되풀이되는 요소를 사용하는 경우도 찾아볼 수 있습니다. </dd> + <dt>footer</dt> + <dd>페이지 바닥의 줄로 일반적으로 작은 정보, 저작권 정보, 또는 연락처 등을 포함하고 있습니다. (header와 같이) 일반적인 정보를 담고 있는 부분이지만 보통 중요하지 않거나 웹 사이트 자체에 부차적인 정보입니다. Footer는 또 가끔 {{Glossary("SEO")}} 목적으로 사용되는데, 인기 컨텐츠 바로가기 링크를 제공합니다.</dd> +</dl> + +<p>"전형적인 웹사이트"는 다음과 같이 구성될 수 있습니다:</p> + +<p><img alt="a simple website structure example featuring a main heading, navigation menu, main content, side bar, and footer." src="https://mdn.mozillademos.org/files/12417/sample-website.png" style="display: block; margin: 0 auto;"></p> + +<h2 id="컨텐츠_구조화를_위한_HTML">컨텐츠 구조화를 위한 HTML</h2> + +<p>위에 보이는 간단한 예제는 아름답지는 않습니다. 하지만 전형적인 웹사이트 레이아웃을 보여주기에는 모자람이 없는 예제입니다. 어떤 웹사이트는 Column이 더 있을 수 있고, 더 복잡할 수 있습니다 하지만 아이디어가 있고 적절한 CSS를 활용한다면, 모든 요소를 활용하여 section별로 구분하여 당신이 원하는 모양으로 만들 수 있습니다. 하지만 이를 논의하기 전에, 우리는 semantic을 고려해서 (요소의 의미를 고려해서) <strong>요소를 적재적소에 사용해야 합니다</strong>.</p> + +<p>This is because visuals don't tell the whole story. We use color and font size to draw sighted users' attention to the most useful parts of the content, like the navigation menu and related links, but what about visually impaired people for example, who might not find concepts like "pink" and "large font" very useful?</p> + +<div class="note"> +<p><strong>Note</strong>: Colorblind people represent around <a href="http://www.color-blindness.com/2006/04/28/colorblind-population/">8% of the world population</a>. Blind and visually impaired people represent roughly 4-5% of the world population (in 2012 there were <a href="https://en.wikipedia.org/wiki/Visual_impairment">285 million such people in the world</a>, while the total population was <a href="https://en.wikipedia.org/wiki/World_human_population#/media/File:World_population_history.svg">around 7 billion</a>.)</p> +</div> + +<p>In your HTML code, you can mark up sections of content based on their <em>functionality</em> — you can use elements that represent the sections of content described above unambiguously, and assistive technologies like screenreaders can recognise those elements and help with tasks like "find the main navigation", or "find the main content." As we mentioned earlier in the course, there are a number of <a href="/en-US/Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals#Why_do_we_need_structure">consequences of not using the right element structure and semantics for the right job</a>.</p> + +<p>To implement such semantic mark up, HTML provides dedicated tags that you can use to represent such sections, for example:</p> + +<ul> + <li><strong>header: </strong>{{htmlelement("header")}}.</li> + <li><strong>navigation bar: </strong>{{htmlelement("nav")}}.</li> + <li><strong>main content: </strong>{{htmlelement("main")}}, with various content subsections represented by {{HTMLElement("article")}}, {{htmlelement("section")}}, and {{htmlelement("div")}} elements.</li> + <li><strong>sidebar: </strong>{{htmlelement("aside")}}; often placed inside {{htmlelement("main")}}.</li> + <li><strong>footer: </strong>{{htmlelement("footer")}}.</li> +</ul> + +<h3 id="Active_learning_exploring_the_code_for_our_example">Active learning: exploring the code for our example</h3> + +<p>Our example seen above is represented by the following code (you can also <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/document_and_website_structure/index.html">find the example in our Github repo</a>). We'd like you to look at the example above, and then look over the listing below to see what parts make up what section of the visual.</p> + +<pre class="brush: html notranslate"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + + <title>My page title</title> + <link href="https://fonts.googleapis.com/css?family=Open+Sans+Condensed:300|Sonsie+One" rel="stylesheet" type="text/css"> + <link rel="stylesheet" href="style.css"> + + <!-- the below three lines are a fix to get HTML5 semantic elements working in old versions of Internet Explorer--> + <!--[if lt IE 9]> + <script src="https://cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.js"></script> + <![endif]--> + </head> + + <body> + <!-- Here is our main header that is used across all the pages of our website --> + + <header> + <h1>Header</h1> + </header> + + <nav> + <ul> + <li><a href="#">Home</a></li> + <li><a href="#">Our team</a></li> + <li><a href="#">Projects</a></li> + <li><a href="#">Contact</a></li> + </ul> + + <!-- A Search form is another commmon non-linear way to navigate through a website. --> + + <form> + <input type="search" name="q" placeholder="Search query"> + <input type="submit" value="Go!"> + </form> + </nav> + + <!-- Here is our page's main content --> + <main> + + <!-- It contains an article --> + <article> + <h2>Article heading</h2> + + <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Donec a diam lectus. Set sit amet ipsum mauris. Maecenas congue ligula as quam viverra nec consectetur ant hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur.</p> + + <h3>subsection</h3> + + <p>Donec ut librero sed accu vehicula ultricies a non tortor. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aenean ut gravida lorem. Ut turpis felis, pulvinar a semper sed, adipiscing id dolor.</p> + + <p>Pelientesque auctor nisi id magna consequat sagittis. Curabitur dapibus, enim sit amet elit pharetra tincidunt feugiat nist imperdiet. Ut convallis libero in urna ultrices accumsan. Donec sed odio eros.</p> + + <h3>Another subsection</h3> + + <p>Donec viverra mi quis quam pulvinar at malesuada arcu rhoncus. Cum soclis natoque penatibus et manis dis parturient montes, nascetur ridiculus mus. In rutrum accumsan ultricies. Mauris vitae nisi at sem facilisis semper ac in est.</p> + + <p>Vivamus fermentum semper porta. Nunc diam velit, adipscing ut tristique vitae sagittis vel odio. Maecenas convallis ullamcorper ultricied. Curabitur ornare, ligula semper consectetur sagittis, nisi diam iaculis velit, is fringille sem nunc vet mi.</p> + </article> + + <!-- the aside content can also be nested within the main content --> + <aside> + <h2>Related</h2> + + <ul> + <li><a href="#">Oh I do like to be beside the seaside</a></li> + <li><a href="#">Oh I do like to be beside the sea</a></li> + <li><a href="#">Although in the North of England</a></li> + <li><a href="#">It never stops raining</a></li> + <li><a href="#">Oh well...</a></li> + </ul> + </aside> + + </main> + + <!-- And here is our main footer that is used across all the pages of our website --> + + <footer> + <p>©Copyright 2050 by nobody. All rights reversed.</p> + </footer> + + </body> +</html></pre> + +<p>Take some time to look over the code and understand it — the comments inside the code should also help you to understand it. We aren't asking you to do much else in this article, because the key to understanding document layout is writing a sound HTML structure, and then laying it out with CSS. We'll wait for this until you start to study CSS layout as part of the CSS topic.</p> + +<h2 id="HTML_레이아웃_요소의_세부_사항">HTML 레이아웃 요소의 세부 사항</h2> + +<p>It's good to understand the overall meaning of all the HTML sectioning elements in detail — this is something you'll work on gradually as you start to get more experience with web development. You can find a lot of detail by reading our <a href="/en-US/docs/Web/HTML/Element">HTML element reference</a>. For now, these are the main definitions that you should try to understand:</p> + +<ul> + <li>{{HTMLElement('main')}} 는 그 <em>페이지에 독자적인</em> 컨텐츠입니다<em>. </em>Use <code><main></code> only <em>once </em>per page, and put it directly inside {{HTMLElement('body')}}. Ideally this shouldn't be nested within other elements.</li> + <li>{{HTMLElement('article')}} encloses a block of related content that makes sense on its own without the rest of the page (e.g. a single blog post.)</li> + <li>{{HTMLElement('section')}} is similar to <code><article></code>, but it is more for grouping together a single part of the page that constitutes one single piece of functionality (e.g. a mini map, or a set of article headlines and summaries.) It's considered best practice to begin each section with a <a href="/en-US/Learn/HTML/Howto/Set_up_a_proper_title_hierarchy">heading</a>; also note that you can break <code><article></code>s up into different <code><section></code>s, or <code><section></code>s up into different <code><article></code>s, depending on the context.</li> + <li>{{HTMLElement('aside')}} contains content that is not directly related to the main content but can provide additional information indirectly related to it (glossary entries, author biography, related links, etc.)</li> + <li>{{HTMLElement('header')}} represents a group of introductory content. If it is a child of {{HTMLElement('body')}} it defines the global header of a webpage, but if it's a child of an {{HTMLElement('article')}} or {{HTMLElement('section')}} it defines a specific header for that section (try not to confuse this with <a href="/en-US/Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML#Adding_a_title">titles and headings</a>.)</li> + <li>{{HTMLElement('nav')}} contains the main navigation functionality for the page. Secondary links, etc., would not go in the navigation.</li> + <li>{{HTMLElement('footer')}} represents a group of end content for a page.</li> +</ul> + +<h3 id="Non-semantic_wrappers">Non-semantic wrappers</h3> + +<p>Sometimes you'll come across a situation where you can't find an ideal semantic element to group some items together or wrap some content. Sometimes you might want to just group a set of elements together to affect them all as a single entity with some {{glossary("CSS")}} or {{glossary("JavaScript")}}. For cases like these, HTML provides the {{HTMLElement("div")}} and {{HTMLElement("span")}} elements. You should use these preferably with a suitable {{htmlattrxref('class')}} attribute, to provide some kind of label for them so they can be easily targeted.</p> + +<p>{{HTMLElement("span")}} is an inline non-semantic element, which you should only use if you can't think of a better semantic text element to wrap your content, or don't want to add any specific meaning. For example:</p> + +<pre class="brush: html notranslate"><p>The King walked drunkenly back to his room at 01:00, the beer doing nothing to aid +him as he staggered through the door <span class="editor-note">[Editor's note: At this point in the +play, the lights should be down low]</span>.</p></pre> + +<p>In this case, the editor's note is supposed to merely provide extra direction for the director of the play; it is not supposed to have extra semantic meaning. For sighted users, CSS would perhaps be used to distance the note slightly from the main text.</p> + +<p>{{HTMLElement("div")}} is a block level non-semantic element, which you should only use if you can't think of a better semantic block element to use, or don't want to add any specific meaning. For example, imagine a shopping cart widget that you could choose to pull up at any point during your time on an e-commerce site:</p> + +<pre class="brush: html notranslate"><div class="shopping-cart"> + <h2>Shopping cart</h2> + <ul> + <li> + <p><a href=""><strong>Silver earrings</strong></a>: $99.95.</p> + <img src="../products/3333-0985/thumb.png" alt="Silver earrings"> + </li> + <li> + ... + </li> + </ul> + <p>Total cost: $237.89</p> +</div></pre> + +<p>This isn't really an <code><aside></code>, as it doesn't necessarily relate to the main content of the page (you want it viewable from anywhere.) It doesn't even particularly warrant using a <code><section></code>, as it isn't part of the main content of the page. So a <code><div></code> is fine in this case. We've included a heading as a signpost to aid screenreader users in finding it.</p> + +<div class="warning"> +<p><strong>Warning</strong>: Divs are so convenient to use that it's easy to use them too much. As they carry no semantic value, they just clutter your HTML code. Take care to use them only when there is no better semantic solution and try to reduce their usage to the minimum otherwise you'll have a hard time updating and maintaining your documents.</p> +</div> + +<h3 id="Line_breaks_and_horizontal_rules">Line breaks and horizontal rules</h3> + +<p>Two elements that you'll use occasionally and will want to know about are {{htmlelement("br")}} and {{htmlelement("hr")}}:</p> + +<p><code><br></code> creates a line break in a paragraph; it is the only way to force a rigid structure in a situation where you want a series of fixed short lines, such as in a postal address or a poem. For example:</p> + +<pre class="brush: html notranslate"><p>There once was a girl called Nell<br> +Who loved to write HTML<br> +But her structure was bad, her semantics were sad<br> +and her markup didn't read very well.</p></pre> + +<p>Without the <code><br></code> elements, the paragraph would just be rendered in one long line (as we said earlier in the course, <a href="/en-US/Learn/HTML/Introduction_to_HTML/Getting_started#Whitespace_in_HTML">HTML ignores most whitespace</a>); with them in the code, the markup renders like this:</p> + +<p>There once was a girl called Nell<br> + Who loved to write HTML<br> + But her structure was bad, her semantics were sad<br> + and her markup didn't read very well.</p> + +<p><code><hr></code> elements create a horizontal rule in the document that denotes a thematic change in the text (such as a change in topic or scene). Visually it just look like a horizontal line. As an example:</p> + +<pre class="notranslate"><p>Ron was backed into a corner by the marauding netherbeasts. Scared, but determined to protect his friends, he raised his wand and prepared to do battle, hoping that his distress call had made it through.</p> +<hr> +<p>Meanwhile, Harry was sitting at home, staring at his royalty statement and pondering when the next spin off series would come out, when an enchanted distress letter flew through his window and landed in his lap. He read it hasily, and lept to his feet; "better get back to work then", he mused.</p></pre> + +<p>Would render like this:</p> + +<p>Ron was backed into a corner by the marauding netherbeasts. Scared, but determined to protect his friends, he raised his wand and prepared to do battle, hoping that his distress call had made it through.</p> + +<hr> +<p>Meanwhile, Harry was sitting at home, staring at his royalty statement and pondering when the next spin off series would come out, when an enchanted distress letter flew through his window and landed in his lap. He read it hasily and sighed; "better get back to work then", he mused.</p> + +<h2 id="간단한_웹사이트_계획하기">간단한 웹사이트 계획하기</h2> + +<p>Once you've planned out the content of a simple webpage, the next logical step is to try to work out what content you want to put on a whole website, what pages you need, and how they should be arranged and link to one another for the best possible user experience. This is called {{glossary("Information architecture")}}. In a large, complex website, a lot of planning can go into this process, but for a simple website of a few pages this can be fairly simple, and fun!</p> + +<ol> + <li>몇 요소들은 대부분의 페이지에 공통적으로 적용될 것이란 걸 명심하세요 — 네비게이션 메뉴나 footer 컨텐츠처럼. 예를 들어 비즈니스를 위한 페이지라면, 당신의 연락처를 각각의 페이지의 footer에 보이도록 하는 것은 좋은 생각입니다. 모든 페이지에 공통적으로 포함하고 싶은 것을 적어보세요.<img alt="the common features of the travel site to go on every page: title and logo, contact, copyright, terms and conditions, language chooser, accessibility policy" src="https://mdn.mozillademos.org/files/12423/common-features.png" style="border-style: solid; border-width: 1px; display: block; height: 375px; margin: 0px auto; width: 600px;"></li> + <li>다음으로, 각 페이지의 구조를 간단한 스케치로 그리세요.아마 위의 우리의 간단한 웹사이트 같을 것입니다). 각 블럭의 기능을 적으세요.<img alt="A simple diagram of a sample site structure, with a header, main content area, two optional sidebars, and footer" src="https://mdn.mozillademos.org/files/12429/site-structure.png" style="border-style: solid; border-width: 1px; display: block; height: 232px; margin: 0px auto; width: 600px;"></li> + <li>이제 웹사이트에 포함시키길 원하는 (각 페이지에 공통적이지 않은) 다른 모든 컨텐츠를 brainstorm하세요 - 리스트에 모두 적어 내려가세요. <img alt="A long list of all the features that we could put on our travel site, from searching, to special offers and country-specific info" src="https://mdn.mozillademos.org/files/12425/feature-list.png" style="border-style: solid; border-width: 1px; display: block; height: 1066px; margin: 0px auto; width: 600px;"></li> + <li>다음으로, 이 모든 컨텐츠들을 그룹화 해 다른 페이지에서 어떤 부분들이 함께할 수 있을지 생각할 수 있습니다. 이것은 {{glossary("Card sorting")}}이라는 기술과 매우 유사합니다.<img alt="The items that should appear on a holiday site sorted into 5 categories: Search, Specials, Country-specific info, Search results, and Buy things" src="https://mdn.mozillademos.org/files/12421/card-sorting.png" style="border-style: solid; border-width: 1px; display: block; height: 579px; margin: 0px auto; width: 600px;"></li> + <li>이제 대략적인 사이트맵을 그려보세요 - 사이트의 각 페이지를 동그라미로 지정하고, 각 페이지 간 동작 흐름을 보여주기 위해 선을 그으세요. 홈페이지는 아마 가운데에 있고, 모두는 아니어도 대부분에 연결될 것 입니다; 작은 사이트 안의 대부분의 페이지는, 비록 예외는 있겠지만, 메인 네비게이션에서 사용할 수 있어야 합니다. 당신은 아마 이것들이 어떻게 보여져야 할지에 대한 설명도 적고 싶을 것입니다. <img alt="A map of the site showing the homepage, country page, search results, specials page, checkout, and buy page" src="https://mdn.mozillademos.org/files/12427/site-map.png" style="border-style: solid; border-width: 1px; display: block; height: 872px; margin: 0px auto; width: 600px;"></li> +</ol> + +<h3 id="Active_learning_create_your_own_sitemap">Active learning: create your own sitemap</h3> + +<p>Try carrying out the above exercise for a website of your own creation. What would you like to make a site about?</p> + +<div class="note"> +<p><strong>Note</strong>: 작업물을 어딘가에 저장하세요; 나중에 필요할 수 도 있습니다.</p> +</div> + +<h2 id="Summary">Summary</h2> + +<p>At this point you should have a better idea about how to structure a web page/site. In the last article of this module, we'll study how to debug HTML.</p> + +<h2 id="See_also">See also</h2> + +<ul> + <li><a href="/en-US/docs/Web/Guide/HTML/Using_HTML_sections_and_outlines">Using HTML sections and outlines</a>: Advanced guide to HTML5 semantic elements and the HTML5 outline algorithm.</li> +</ul> + +<p>{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/Advanced_text_formatting", "Learn/HTML/Introduction_to_HTML/Debugging_HTML", "Learn/HTML/Introduction_to_HTML")}}</p> diff --git a/files/ko/learn/html/introduction_to_html/getting_started/index.html b/files/ko/learn/html/introduction_to_html/getting_started/index.html new file mode 100644 index 0000000000..319f8031db --- /dev/null +++ b/files/ko/learn/html/introduction_to_html/getting_started/index.html @@ -0,0 +1,725 @@ +--- +title: HTML 시작하기 +slug: Learn/HTML/Introduction_to_HTML/Getting_started +translation_of: Learn/HTML/Introduction_to_HTML/Getting_started +--- +<div>{{LearnSidebar}}</div> + +<div>{{NextMenu("Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML", "Learn/HTML/Introduction_to_HTML")}}</div> + +<p class="summary">이 문서는 HTML 의 기본적인 내용에 대한 글입니다. 이 글에서는 HTML 에 관련된 용어들(Element, Attribute ..)의 정의에 대해 설명할 것입니다. 또한 HTML이 무엇으로 이루어져 있는지(구성요소), 어떻게 구성되어 있는지(구조), 중요한 특징은 무엇인지에 대해 설명할 것입니다. 독자의 흥미를 위해 간단한 HTML 을 작성하는 과정도 포함되어 있습니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">사전 지식</th> + <td>기본적인 컴퓨터의 이해, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Installing_basic_software">기본 소프트웨어 설치하기</a>, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Dealing_with_files">파일 다루기</a>의 기본적 지식.</td> + </tr> + <tr> + <th scope="row">목표</th> + <td>HTML언어에 대해 익숙해지고, HTML을 이용하여 실습해봅니다.</td> + </tr> + </tbody> +</table> + +<h2 id="HTML이란">HTML이란?</h2> + +<p>{{glossary("HTML")}} (Hypertext Markup Language,하이퍼텍스트 마크업 언어)는 프로그래밍 언어는 아니고, 우리가 보는 웹페이지가 어떻게 구조화되어 있는지 브라우저로 하여금 알 수 있도록 하는 마크업 언어입니다. 이는 개발자로 하여금 복잡하게도 간단하게도 프로그래밍 할 수 있습니다. HTML은 {{glossary("Element", "elements")}}로 구성되어 있으며, 이들은 적절한 방법으로 나타내고 실행하기 위해 각 컨텐츠의 여러 부분들을 감싸고 마크업 합니다. {{glossary("Tag", "tags")}} 는 웹 상의 다른 페이지로 이동하게 하는 하이퍼링크 내용들을 생성하거나, 단어를 강조하는 등의 역할을 합니다. 예를들어, 다음의 내용을 봅시다.</p> + +<pre class="notranslate">My cat is very grumpy</pre> + +<p>만약 다음의 문장을 그냥 그 자체로 표시하고 싶다면, 태그 중 ({{htmlelement("p")}})로 감싸 엘리먼트를 문단으로 명시할 수 있습니다.</p> + +<pre class="brush: html notranslate"><p>My cat is very grumpy</p></pre> + +<div class="note"> +<p><strong>참고</strong>: HTML 요소는 대소문자를 구분하지 않습니다. 그 말은 {{htmlelement("title")}} 요소는 <code><title></code>, <code><TITLE></code>, <code><Title></code>, <code><TiTlE></code> 들과 같이 사용할 수 있습니다. 하지만 대게는 가독성과 기타 이유때문에 소문자로 작성합니다.</p> +</div> + +<h2 id="HTML_요소Element의_구조">HTML 요소(Element)의 구조</h2> + +<p>HTML에서의 요소에 대해 좀 더 알아봅시다.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/9347/grumpy-cat-small.png" style="display: block; height: 255px; margin: 0px auto; width: 821px;"></p> + +<p>엘리먼트의 주요 부분은 다음과 같습니다.</p> + +<ol> + <li><strong>여는 태그(Opening tag):</strong> 이것은 요소의 이름과(이 경우 p), 열고 닫는 꺽쇠 괄호로 구성됩니다. 요소가 시작(이 경우 단락의 시작 부분)부터 효과가 적용되기 시작합니다.</li> + <li><strong>닫는 태그(Closing tag):</strong> 이것은 요소의 이름 앞에 슬래시(/)가 있는것을 제외하면 여는 태그(opening tag)와 같습니다. 이것은 요소의 끝(이 경우 단락의 끝 부분)에 위치합니다. 닫는 태그를 적어주지 않는 것은 흔한 초심자의 오류이며, 이것은 이상한 결과를 낳게됩니다.</li> + <li><strong>내용(Content):</strong> 요소의 내용이며, 이 경우 단순한 텍스트이다.</li> + <li><strong>요소(Element):</strong> 여는 태그, 닫는 태그, 내용을 통틀어 요소(element)라고한다.</li> +</ol> + +<h3 id="실습_첫_번째_HTML_요소_만들어보기">실습: 첫 번째 HTML 요소 만들어보기</h3> + +<p>Input 영역 아래의 줄을 <code><em></code> 과 <code></em></code> 태그를 이용해서 감싸 보세요. (줄의 앞에 요소를 열기위해 <code><em></code>태그를, 뒤에는 요소를 닫기위해 <code></em></code>태그를 두세요.) — 이것은 그 줄에 이탤릭강조효과를 줍니다! 여러분이 수정하는 결과는 실시간으로 Output 영역에서 볼 수 있습니다.</p> + +<p>만약 실수를 했다면, 언제든지 Reset 버튼을 눌러서 초기화 할 수 있습니다. 만약 아무래도 답을 모르겠다면, Show solution 버튼을 이용해서 답을 볼 수 있습니다.</p> + +<div class="hidden"> +<h6 id="Playable_code">Playable code</h6> + +<pre class="brush: html notranslate"><h2>Live output</h2> +<div class="output" style="min-height: 50px;"> +</div> + +<h2>Editable code</h2> +<p class="a11y-label">코드 영역에서 포커스를 이동하려면 Esc키를 누르십시오 (Tab키로 탭 문자를 삽입).</p> + +<textarea id="code" class="input" style="min-height: 100px; width: 95%"> + This is my text. +</textarea> + +<div class="controls"> + <input id="reset" type="button" value="Reset" /> + <input id="solution" type="button" value="Show solution" /> +</div> +</pre> + +<pre class="brush: css notranslate">html { + font-family: 'Open Sans Light',Helvetica,Arial,sans-serif; +} + +h2 { + font-size: 16px; +} + +.a11y-label { + margin: 0; + text-align: right; + font-size: 0.7rem; + width: 98%; +} + +body { + margin: 10px; + background: #f5f9fa; +} +</pre> + +<pre class="brush: js notranslate">var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var output = document.querySelector('.output'); +var code = textarea.value; +var userEntry = textarea.value; + +function updateCode() { + output.innerHTML = textarea.value; +} + +reset.addEventListener('click', function() { + textarea.value = code; + userEntry = textarea.value; + solutionEntry = htmlSolution; + solution.value = 'Show solution'; + updateCode(); +}); + +solution.addEventListener('click', function() { + if(solution.value === 'Show solution') { + textarea.value = solutionEntry; + solution.value = 'Hide solution'; + } else { + textarea.value = userEntry; + solution.value = 'Show solution'; + } + updateCode(); +}); + +var htmlSolution = '<em>This is my text.</em>'; +var solutionEntry = htmlSolution; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); + +// stop tab key tabbing out of textarea and +// make it write a tab at the caret position instead + +textarea.onkeydown = function(e){ + if (e.keyCode === 9) { + e.preventDefault(); + insertAtCaret('\t'); + } + + if (e.keyCode === 27) { + textarea.blur(); + } +}; + +function insertAtCaret(text) { + var scrollPos = textarea.scrollTop; + var caretPos = textarea.selectionStart; + + var front = (textarea.value).substring(0, caretPos); + var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length); + textarea.value = front + text + back; + caretPos = caretPos + text.length; + textarea.selectionStart = caretPos; + textarea.selectionEnd = caretPos; + textarea.focus(); + textarea.scrollTop = scrollPos; +} + +// Update the saved userCode every time the user updates the text area code + +textarea.onkeyup = function(){ + // We only want to save the state when the user code is being shown, + // not the solution, so that solution is not saved over the user code + if(solution.value === 'Show solution') { + userEntry = textarea.value; + } else { + solutionEntry = textarea.value; + } + + updateCode(); +};</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code', 700, 400, "", "", "hide-codepen-jsfiddle") }}</p> + +<h3 id="포함내포內包된_요소Nesting_elements">포함(내포:內包)된 요소(Nesting elements)</h3> + +<p>요소 안에 다른 요소가 들어갈 수 있습니다. 그런 요소는 내포되었다고 표현합니다. "고양이가 매우 사납다" 라는 문단을 강조하기 위해서, '매우'라는 단어를 강조하는 {{htmlelement("strong")}} 요소를 중첩해서 사용할 수 있습니다.</p> + +<pre class="brush: html notranslate"><p>My cat is <strong>very</strong> grumpy.</p></pre> + +<p>요소 내표를 위해서는 확인해야 할 것이 있습니다. 위의 예제에서는 <code>p</code> 요소가 먼저 열렸고, 그리고 <code>strong</code> 요소가 열렸습니다. 그렇기 때문에 <code>strong</code> 요소가 먼저 닫힌 후에 <code>p</code> 요소가 닫혀야 합니다. 아래와 같은 문장은 중첩(重疊 : 서로 포개어(overlap 또는 stacking) 지거나, 엇갈려 겹쳐짐)되었으므로 잘못된 문장입니다.</p> + +<pre class="example-bad brush: html notranslate"><p>My cat is <strong>very grumpy.</p></strong></pre> + +<p>요소 내포을 위해서, 내포되어 지는 요소는 다른 요소 속에서 열고 닫혀야 하며 다른 요소를 포함시키는 요소는 그 바깥에서 열고 닫혀야 합니다. 위의 잘못된 예제와 같이 내포가 제대로 되지 않았을 경우엔 웹 브라우저가 임의로 결과를 보일 것이며, 그것은 원치않는 것일 수 있습니다. 그런데 잘못 된 내포에도 불구하고 어떤 브라우저에서 이상없이 보일 수도 있습니다. 하지만 그 것은 그저 그 브라우저가 문법에 흐물흐물(permittable)해서 웬만한 오류는 자체 수정해서 브라우저 창에 rendering해주기 때문일 뿐 입니다. '웬만한 오류는 알아서 처리해 준다.' 는 부분에서 초보자는 특히 주의해야 합니다.</p> + +<h3 id="블럭_레벨_요소_vs_인라인_요소Block_versus_inline_elements">블럭 레벨 요소 vs 인라인 요소(Block versus inline elements)</h3> + +<p>HTML에는 두가지 종류의 요소(Element) 가 있습니다. 블록 레벨 요소(Block level element) 와 인라인 요소(Inline element) 입니다.</p> + +<ul> + <li>블록 레벨 요소(Block-level elements) 는 웹페이지 상에 블록(Block)을 만드는 요소입니다. 블록 레벨 요소는 앞뒤 요소 사이에 새로운 줄(Line)을 만들고 나타납니다. 즉 블록 레벨 요소 이전과 이후 요소사이의 줄을 바꿉니다. 블록 레벨 요소는 일반적으로 페이지의 구조적 요소를 나타낼 때 사용됩니다. 예를 들어 개발자는 블록 레벨 요소를 사용하여 단락(Paragraphs), 목록(lists), 네비게이션 메뉴(Navigation Menus), 꼬리말(Footers) 등을 표현할 수 있습니다. 블록 레벨 요소는 인라인 요소(Inline elements)에 중첩될(Nested inside)수 없습니다. 그러나 블록 레벨 요소는 다른 블록 레벨 요소에 중첩될 수 있습니다. </li> + <li>인라인 요소(Inline elements)는 항상 블록 레벨 요소내에 포함되어 있습니다. 인라인 요소는 문서의 한 단락같은 큰 범위에는 적용될 수 없고 문장, 단어 같은 작은 부분에 대해서만 적용될 수 있습니다. 인라인 요소는 새로운 줄(Line)을 만들지 않습니다. 즉 인라인 요소를 작성하면 그것을 작성한 단락내에 나타나게 됩니다. 예를 들어, 인라인 요소에는 하이퍼링크를 정의하는 요소인 {{htmlelement("a")}} , 텍스트(Text)를 강조하는 요소인 {{htmlelement("em")}},{{htmlelement("strong")}} 등이 있습니다.</li> +</ul> + +<p>다음 예시를 봅시다:</p> + +<pre class="brush: html notranslate"><em>first</em><em>second</em><em>third</em> + +<p>fourth</p><p>fifth</p><p>sixth</p> +</pre> + +<p>{{htmlelement("em")}} 은 인라인 요소(inline element) 이므로, 밑에서 보실 수 있듯이, 처음 세 개의 요소는 서로 같은 줄에, 사이에 공백이 없이 위치합니다. 한편, {{htmlelement("p")}} 는 블록 레벨 요소이므로, 각 요소들은 새로운 줄에 나타나며, 위와 아래에 여백이 있습니다 (여백은 브라우저가 문단에 적용하는 기본 <a href="/en-US/docs/Learn/CSS/Introduction_to_CSS">CSS styling</a> 때문에 적용됩니다).</p> + +<p>{{ EmbedLiveSample('Block_versus_inline_elements', 700, 200, "", "") }}</p> + +<div class="note"> +<p><strong>참고</strong>: HTML5에서 요소 분류를 재정의 했습니다: <a href="http://www.whatwg.org/specs/web-apps/current-work/complete/section-index.html#element-content-categories">Element content categories</a>. 이러한 정의는 이전의 정의보다 더 정확하고 덜 모호하지만, "블록"과 "인라인"보다 이해하기 훨씬 더 복잡하기 때문에, 이 주제 내내 이 정의들을 고수할 것입니다.</p> +</div> + +<div class="note"> +<p><strong>참고</strong>: 이 주제에서 사용되는 "블럭(block)"과 "인라인(inline)"의 뜻은 <a href="https://developer.mozilla.org/en-US/docs/Learn/CSS/Introduction_to_CSS/Box_model#Types_of_CSS_boxes">the types of CSS boxes</a>에서 사용하고 있는 같은 단어와 혼돈하면 안 됩니다. 기본적으로는 상관관계가 있지만 CSS 표시 유형을 변경해도 요소의 범주는 변경되지 않으며 요소가 포함할 수 있는 요소와 요소가 포함될 수 있는 요소에는 영향을 주지 않는다. HTML5가 이러한 용어들을 삭제했던 이유 중 하나는 이러한 다소 흔한 혼란을 막기 위해서였다.</p> +</div> + +<div class="note"> +<p><strong>참고</strong>: <a href="/en-US/docs/Web/HTML/Block-level_elements">Block-level elements</a>문서와 <a href="/en-US/docs/Web/HTML/Inline_elements">Inline elements</a>문서를 참고하면 블럭과 인라인 요소에 대한 유용한 내용을 찾을 수 있습니다.</p> +</div> + +<h3 id="빈_요소Empty_elements">빈 요소(Empty elements)</h3> + +<p>모든 요소가 위에 언급된 여는 태그, 내용, 닫는 태그 패턴을 따르는 것은 아닙니다. 주로 문서에 무언가를 첨부하기 위해 단일 태그(Single tag)를 사용하는 요소도 있습니다. 예를 들어 {{htmlelement("img")}} 요소는 해당 위치에 이미지를 삽입하기 위한 요소입니다:</p> + +<pre class="brush: html notranslate"><img src="https://raw.githubusercontent.com/mdn/beginner-html-site/gh-pages/images/firefox-icon.png"></pre> + +<p>위에 대한 결과는 다음과 같이 나올 것입니다:</p> + +<p>{{ EmbedLiveSample('Empty_elements', 700, 300, "", "", "hide-codepen-jsfiddle") }}</p> + +<div class="note"> +<p><strong>참고</strong>: 빈 요소는 가끔 Void 요소로 불리기도 합니다.</p> +</div> + +<h2 id="속성Attributes">속성(Attributes)</h2> + +<p>요소는 아래 이미지와 같이 속성을 가질 수 있습니다:</p> + +<p><img alt='&amp;amp;lt;p class="editor-note">My cat is very grumpy&amp;amp;lt;/p>' src="https://mdn.mozillademos.org/files/9345/grumpy-cat-attribute-small.png" style="display: block; height: 156px; margin: 0px auto; width: 1287px;"></p> + +<p>속성은 요소에 실제론 나타내고 싶지 않지만 추가적인 내용을 담고 싶을 때 사용합니다. 위에는 나중에 스타일에 관련된 내용이나 기타 내용을 위해 해당 목표를 구분할 수 있는 <code>class</code> 속성을 부여했습니다.</p> + +<p>속성을 사용할 때에는 아래 내용을 지켜야 합니다:</p> + +<ol> + <li>요소 이름 다음에 바로 오는 속성은 요소 이름과 속성 사이에 공백이 있어야 되고, 하나 이상의 속성들이 있는 경우엔 속성 사이에 공백이 있어야 합니다.</li> + <li>속성 이름 다음엔 등호(=)가 붙습니다.</li> + <li>속성 값은 열고 닫는 따옴표로 감싸야 합니다.</li> +</ol> + +<h3 id="실습_요소에_속성_추가하기">실습: 요소에 속성 추가하기</h3> + +<p>또다른 요소 중 하나인 {{htmlelement("a")}} 요소는 "anchor"를 의미하는데, 닻이 배를 항구로 연결하듯 텍스트를 감싸서 하이퍼링크로 만듭니다. 이 요소는 여러 속성을 가질 수 있지만 아래에 있는 두 개가 주로 사용됩니다:</p> + +<ul> + <li><code>href</code>: 이 속성에는 당신이 연결하고자 하는 웹 주소를 지정합니다. 그 예로, <code>href="https://www.mozilla.org/"</code>.</li> + <li><code>title</code>: <code>title</code> 속성은 링크에 대한 추가 정보를 나타냅니다. 그 예로, <code>title="The Mozilla homepage"</code>. 이 내용은 링크 위로 마우스를 옮겼을 때 나타날 것입니다.</li> + <li><code>target</code>: <code>target</code> 속성은 링크가 어떻게 열릴 것인지를 지정합니다. 예를 들어, <code>target="_blank"</code> 는 링크를 새 탭에서 보여줍니다. 당신이 현재 탭에서 링크를 보여주고싶다면 이 속성을 생략하면 됩니다.</li> +</ul> + +<p>당신이 즐겨 찾는 웹 사이트에 대한 링크를 만들기 위해 아래 입력 영역에서 행을 편집해 봅시다. 첫 번째로, <code><a></code> 요소를 추가합니다. 다음으로 <code>href</code> 속성과 <code>title</code> 속성을 추가합니다. 마지막으로 새 탭에서 링크를 열도록 <code>target</code> 속성을 지정합니다. 당신은 출력 영역에서 수정사항이 바로 변경되는 것을 볼 수 있습니다. 링크 위에 마우스를 올리면 <code>title</code> 속성 내용이 보여지고, 클릭하면 <code>href</code> 요소의 웹 주소로 이동할 것입니다. 각 요소의 이름과 그 값 사이에는 빈 칸이 필요하다는 것을 기억해야 합니다.</p> + +<p>만약 실수했다면 Reset 버튼을 눌러 처음으로 돌아갈 수 있습니다. 도움이 필요한 경우에는 답을 Show solution 버튼을 눌러 정답을 볼 수 있습니다.</p> + +<div class="hidden"> +<h6 id="Playable_code2">Playable code2</h6> + +<pre class="brush: html notranslate"><code><h2>Live output</h2> + +<div class="output" style="min-height: 50px;"> +</div> + +<h2>Editable code</h2> +<p class="a11y-label">Press Esc to move focus away from the code area (Tab inserts a tab character).</p> + +<textarea id="code" class="input" style="min-height: 100px;width: 95%"> + &lt;p&gt;A link to my favorite website.&lt;/p&gt; +</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Reset"> + <input id="solution" type="button" value="Show solution"> +</div></code></pre> + +<pre class="brush: css notranslate"><code>html { + font-family: sans-serif; +} + +h2 { + font-size: 16px; +} + +.a11y-label { + margin: 0; + text-align: right; + font-size: 0.7rem; + width: 98%; +} + +body { + margin: 10px; + background: #f5f9fa; +}</code></pre> + +<pre class="brush: js notranslate"><code>var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var output = document.querySelector('.output'); +var code = textarea.value; +var userEntry = textarea.value; + +function updateCode() { + output.innerHTML = textarea.value; +} + +reset.addEventListener('click', function() { + textarea.value = code; + userEntry = textarea.value; + solutionEntry = htmlSolution; + solution.value = 'Show solution'; + updateCode(); +}); + +solution.addEventListener('click', function() { + if(solution.value === 'Show solution') { + textarea.value = solutionEntry; + solution.value = 'Hide solution'; + } else { + textarea.value = userEntry; + solution.value = 'Show solution'; + } + updateCode(); +}); + +var htmlSolution = '<p>A link to my <a href="https://www.mozilla.org/" title="The Mozilla homepage" target="_blank">favorite website</a>.</p>'; +var solutionEntry = htmlSolution; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); + +// stop tab key tabbing out of textarea and +// make it write a tab at the caret position instead + +textarea.onkeydown = function(e){ + if (e.keyCode === 9) { + e.preventDefault(); + insertAtCaret('\t'); + } + + if (e.keyCode === 27) { + textarea.blur(); + } +}; + +function insertAtCaret(text) { + var scrollPos = textarea.scrollTop; + var caretPos = textarea.selectionStart; + + var front = (textarea.value).substring(0, caretPos); + var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length); + textarea.value = front + text + back; + caretPos = caretPos + text.length; + textarea.selectionStart = caretPos; + textarea.selectionEnd = caretPos; + textarea.focus(); + textarea.scrollTop = scrollPos; +} + +// Update the saved userCode every time the user updates the text area code + +textarea.onkeyup = function(){ + // We only want to save the state when the user code is being shown, + // not the solution, so that solution is not saved over the user code + if(solution.value === 'Show solution') { + userEntry = textarea.value; + } else { + solutionEntry = textarea.value; + } + + updateCode(); +};</code></pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code2', 700, 400, "", "", "hide-codepen-jsfiddle") }}</p> + +<h3 id="참과_거짓_속성Boolean_attributes">참과 거짓 속성(Boolean attributes)</h3> + +<p>때때로 값이 없는 속성을 볼 수 있을텐데 이것은 허용되는 것입니다. 이를 불 속성이라고 하며, 일반적으로 그 속성의 이름과 동일한 하나의 값만을 가질 수 있습니다. 예를 들어 {{htmlattrxref("disabled", "input")}} 속성을 양식 입력 요소에 할당하면 사용자가 데이터를 입력할 수 없도록 비활성화(회색으로 표시) 할 수 있습니다.</p> + +<pre class="notranslate"><input type="text" disabled="disabled"></pre> + +<p>이것은 다음과 같이 줄여쓸 수 있습니다. (당신이 참고할 수 있도록 비활성화를 하지 않은 형태도 포함했습니다.)</p> + +<pre class="brush: html notranslate"><input type="text" disabled> + +<input type="text"></pre> + +<p>이 둘은 다음과 같은 결과를 보여줍니다.</p> + +<p>{{ EmbedLiveSample('Boolean_attributes', 700, 100, "", "", "hide-codepen-jsfiddle") }}</p> + +<h3 id="속성값의_따옴표_생략">속성값의 따옴표 생략</h3> + +<p>웹을 둘러보면 따옴표가 없는 속성값을 포함한 온갖 이상한 마크업 스타일을 볼 것입니다. 어떤 상황에선 이런 것이 허용되지만, 다른 상황에서는 당신의 마크업 형식을 망쳐버립니다. 이전에 작성한 코드에서 우리는 <code>href</code> 속성만 있는 기본적인 버전을 작성했습니다.</p> + +<pre class="brush: html notranslate"><a href=https://www.mozilla.org/>favorite website</a></pre> + +<p>하지만 여기에 <code>title</code> 속성을 추가하면 문제가 발생합니다.</p> + +<pre class="brush: html notranslate"><a href=https://www.mozilla.org/ title=The Mozilla homepage>favorite website</a></pre> + +<p>이 때 브라우저는 당신의 마크업을 잘못 해석해서 title이 세 개의 속성값을 가진다고 생각할 것입니다. <code>title</code> 속성값 "The"와 두 개의 불 속성값 <code>Mozilla</code>, <code>homepage</code>라고 말이죠. 이 것은 우리가 의도한 것도 아닐 뿐더러 아래의 예시처럼 오류가 발생하거나 예상치 못한 동작을 할 수도 있습니다. 링크 위에 마우스를 올려 title이 어떻게 보이는지 확인해 보세요.</p> + +<p>{{ EmbedLiveSample('Omitting_quotes_around_attribute_values', 700, 100, "", "", "hide-codepen-jsfiddle") }}</p> + +<p>우리는 항상 속성값에 따옴표를 붙이라고 조언합니다. 이런 오류를 피할 수도 있고, 코드의 가독성도 좋아지기 때문입니다.</p> + +<h3 id="작은_따옴표_큰_따옴표">작은 따옴표, 큰 따옴표?</h3> + +<p>이 글에서 모든 속성값은 큰 따옴표에 둘러싸여 있는 것을 볼 수 있습니다. 하지만 당신은 어떤 사람의 HTML에서 작은 따옴표를 볼 수 있을 것입니다. 이 것은 스타일의 문제로, 당신이 좋아하는 방법을 사용하면 됩니다. 아래 두 문장은 똑같이 동작합니다.</p> + +<pre class="brush: html notranslate"><a href="http://www.example.com">A link to my example.</a> + +<a href='http://www.example.com'>A link to my example.</a></pre> + +<p>주의해야할 점은 두 개를 섞어 쓰면 안된다는 것입니다. 다음은 잘못 사용한 예입니다.</p> + +<pre class="brush: html notranslate"><a href="http://www.example.com'>A link to my example.</a></pre> + +<p>만약 한 가지 따옴표를 사용했다면 다른 따옴표로 속성값을 둘러싸서 오류를 방지할 수 있습니다.</p> + +<pre class="brush: html notranslate"><a href="http://www.example.com" title="Isn't this fun?">A link to my example.</a></pre> + +<p>하지만 만약 당신이 따옴표 안에 같은 따옴표를 사용하고 싶다면(작은 따옴표든 큰 따옴표든) 따옴표를 표시하기 위해서 <a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Introduction_to_HTML/Getting_started#Entity_references_Including_special_characters_in_HTML">HTML entities</a>를 사용하세요. 예를 들어 이렇게 하면 잘못됩니다.</p> + +<pre class="notranslate"><code><a href='http://www.example.com' title='Isn't this fun?'>A link to my example.</a></code></pre> + +<p>그래서 이렇게 바꿔주면 잘 작동합니다.</p> + +<pre class="notranslate"><code><a href='http://www.example.com' title='Isn&#39;t this fun?'>A link to my example.</a></code></pre> + +<h2 id="HTML_문서의_구조">HTML 문서의 구조</h2> + +<p>That wraps up the basics of individual HTML elements, but they aren't very useful on their own. 이제 어떻게 개별 요소를 결합해 전체 HTML 페이지를 구성하는지에 대해 살펴봅시다.</p> + +<pre class="brush: html notranslate"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>My test page</title> + </head> + <body> + <p>This is my page</p> + </body> +</html></pre> + +<p>여기를 보면,</p> + +<ol> + <li><code><!DOCTYPE html></code>: 문서 형식을 나타냅니다. HTML 초창기에 (1991~2년) doctype은 HTML 페이지가 자동 오류 검사나 다른 유용한 것이 가능한 좋은 HTML을 의미하는 연결고리처럼 작동하는 것을 뜻했습니다. 이런 형식으로 사용했습니다. + + <pre class="notranslate"><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" +"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"></pre> + 하지만 요즘에는 아무도 신경쓰지 않으며, 그저 모든 것이 제대로 작동하기 위해 포함되어야 하는 역사적 유물일 뿐입니다. <code><!DOCTYPE html></code> 은 유효한 문서 형식을 나타내는 짧은 문장이고, 이 것만 알고 있으면 됩니다.</li> + <li><code><html></html></code>: {{htmlelement("html")}} 요소입니다. 이 요소는 전체 페이지의 콘텐츠를 포함하며, 기본 요소로도 알려져 있습니다.</li> + <li><code><head></head></code>: <code><head></code> 요소입니다. 이 요소는 홈페이지 이용자에게는 보이지 않지만 검색 결과에 노출 될 키워드, 홈페이지 설명, CSS 스타일, character setdeclaration 등 HTML 페이지의 모든 내용을 담고 있습니다. 자세한 내용은 다음 장에서 다룹니다.</li> + <li><code><meta charset="utf-8"></code>: 이 요소는 HTML 문서의 문자 인코딩 설정을 UTF-8로 지정하는 것이며 예시에서 지정한 UTF-8에는 전세계에서 사용되는 언어에 대한 대부분의 문자가 포함됩니다. 이 설정을 사용하면 페이지에 포함 된 모든 텍스트 내용을 처리 할 수 있습니다. 이것을 설정하면 나중에 문자 인코딩과 관련된 일부 문제를 피하는 데 도움이 될 수 있으므로 문자 인코딩 설정을 하지 않을 이유가 없습니다.</li> + <li><code><title></title></code>: {{htmlelement ( "title")}} 요소입니다. 이 요소를 사용하면 페이지 제목이 설정되며 페이지가 로드되는 브라우저 탭에 표시되는 제목으로 사용됩니다. 페이지 제목은 페이지가 책갈피 될 때 페이지를 설명하는 데에도 사용됩니다.</li> + <li><code><body></body></code>: {{htmlelement ( "body")}} 요소 여기에는 텍스트, 이미지, 비디오, 게임, 재생 가능한 오디오 트랙 등을 비롯하여 페이지에 표시되는 모든 콘텐츠가 포함됩니다.</li> +</ol> + +<h3 id="실습_HTML_문서에_일부_기능_추가하기">실습: HTML 문서에 일부 기능 추가하기</h3> + +<p>로컬 컴퓨터에서 일부 HTML을 작성하여 실험하고 싶다면 다음을 수행하십시오. </p> + +<ol> + <li>위에 나열된 HTML 페이지 예제를 복사하십시오.</li> + <li>텍스트 편집기에서 새 파일을 작성하십시오.</li> + <li>코드를 새 텍스트 파일에 붙여 넣습니다.</li> + <li>파일을 <code>index.html</code>로 저장하십시오.</li> +</ol> + +<div class="note"> +<p><strong>참고</strong>: 기본 HTML 템플릿은 <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/getting-started/index.html">MDN Learning Area Github repo</a> 에서도 찾을 수 있습니다.</p> +</div> + +<p>이제 웹 브라우저에서 이 파일을 열어 렌더링 된 코드의 모양을 확인할 수 있습니다. 코드를 편집하고 브라우저를 새로 고침하여 결과를 확인하십시오. 첫 페이지는 다음과 같습니다.</p> + +<p><img alt="A simple HTML page that says This is my page" src="https://mdn.mozillademos.org/files/12279/template-screenshot.png" style="display: block; height: 365px; margin: 0px auto; width: 595px;">이 연습에서는 앞에서 설명한대로 컴퓨터에서 로컬로 코드를 편집하거나 아래 샘플 창에서 편집 할 수 있습니다 (편집 가능한 샘플 창은 {{htmlelement ( "body")}} 요소의 내용만 나타냄 이 경우). 다음 작업을 구현하여 기술을 익히십시오.</p> + +<ul> + <li>{{htmlelement ( "body")}} 요소의 시작 태그 바로 아래에 문서의 기본 제목을 추가하십시오. <code><h1></code> 여는 태그와 <code></h1></code> 닫는 태그 안에 싸야합니다.</li> + <li>관심있는 주제에 대한 텍스트를 포함하도록 단락 컨텐츠를 편집하십시오.</li> + <li>중요한 단어는 <code><strong></code> 여는 태그와 <code></ strong></code> 닫는 태그 안에 넣어 굵게 표시하십시오.</li> + <li><a href="/en-US/Learn/HTML/Introduction_to_HTML/Getting_started#Active_learning_Adding_attributes_to_an_element">이 글의 앞부분에서 설명</a>한대로 단락에 대한 링크를 추가하십시오.</li> + <li>문서에 이미지를 추가하십시오. <a href="/en-US/Learn/HTML/Introduction_to_HTML/Getting_started#Empty_elements">이 글의 앞부분에서 설명</a>한대로 단락 아래에 배치하십시오. 다른 이미지 (컴퓨터의 로컬 또는 웹의 다른 위치)에 연결하면 보너스 포인트를 얻을 수 있습니다.</li> +</ul> + +<p>만약 실수한 경우 언제든지 <em>Reset</em> 버튼을 사용하여 초기화 할 수 있습니다. 문제가 발생하면 <em>Show solution</em> 단추를 눌러 답변을 확인하십시오.</p> + +<div class="hidden"> +<h6 id="Playable_code3">Playable code3</h6> + +<pre class="brush: html notranslate"><h2>Live Output</h2> + +<div class="output" style="min-height: 50px"></div> + +<h2>Editable code</h2> +<p class="a11y-label">코드 영역에서 포커스를 이동하려면 Esc 키를 누르십시오 (탭은 탭 문자를 삽입합니다).</p> + +<textarea id="code" class="input" style="min-height: 100px; width: 95%"> + &lt;p&gt;This is my page&lt;/p&gt; +</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Reset" /> + <input id="solution" type="button" value="Show solution" /> +</div> +</pre> + +<pre class="brush: css notranslate">html { + font-family: sans-serif; +} + +h1 { + color: blue; +} + +h2 { + font-size: 16px; +} + +.a11y-label { + margin: 0; + text-align: right; + font-size: 0.7rem; + width: 98%; +} + +img { + max-width: 100%; +} + +body { + margin: 10px; + background: #f5f9fa; +}</pre> + +<pre class="brush: js notranslate">var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var output = document.querySelector('.output'); +var code = textarea.value; +var userEntry = textarea.value; + +function updateCode() { + output.innerHTML = textarea.value; +} + +reset.addEventListener('click', function() { + textarea.value = code; + userEntry = textarea.value; + solutionEntry = htmlSolution; + solution.value = 'Show solution'; + updateCode(); +}); + +solution.addEventListener('click', function() { + if(solution.value === 'Show solution') { + textarea.value = solutionEntry; + solution.value = 'Hide solution'; + } else { + textarea.value = userEntry; + solution.value = 'Show solution'; + } + updateCode(); +}); + +var htmlSolution = '<h1>Some music</h1><p>I really enjoy <strong>playing the drums</strong>. One of my favorite drummers is Neal Peart, who\ plays in the band <a href="https://en.wikipedia.org/wiki/Rush_%28band%29" title="Rush Wikipedia article">Rush</a>.\ My favourite Rush album is currently <a href="http://www.deezer.com/album/942295">Moving Pictures</a>.</p>\ <img src="http://www.cygnus-x1.net/links/rush/images/albums/sectors/sector2-movingpictures-cover-s.jpg">'; +var solutionEntry = htmlSolution; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); + +// stop tab key tabbing out of textarea and +// make it write a tab at the caret position instead + +textarea.onkeydown = function(e){ + if (e.keyCode === 9) { + e.preventDefault(); + insertAtCaret('\t'); + } + + if (e.keyCode === 27) { + textarea.blur(); + } +}; + +function insertAtCaret(text) { + var scrollPos = textarea.scrollTop; + var caretPos = textarea.selectionStart; + + var front = (textarea.value).substring(0, caretPos); + var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length); + textarea.value = front + text + back; + caretPos = caretPos + text.length; + textarea.selectionStart = caretPos; + textarea.selectionEnd = caretPos; + textarea.focus(); + textarea.scrollTop = scrollPos; +} + +// Update the saved userCode every time the user updates the text area code + +textarea.onkeyup = function(){ + // We only want to save the state when the user code is being shown, + // not the solution, so that solution is not saved over the user code + if(solution.value === 'Show solution') { + userEntry = textarea.value; + } else { + solutionEntry = textarea.value; + } + + updateCode(); +};</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code3', 700, 600, "", "", "hide-codepen-jsfiddle") }}</p> + +<h3 id="HTML_공백">HTML 공백</h3> + +<p>위의 예에서 많은 공백이 코드에 포함되어 있음을 알 수 있습니다. 이것은 선택 사항입니다. 이 두 코드 스니펫은 동일합니다.</p> + +<pre class="brush: html notranslate"><p>Dogs are silly.</p> + +<p>Dogs are + silly.</p></pre> + +<p>HTML 요소 내용 내에서 얼마나 많은 공백을 사용하든 (하나 이상의 공백 문자를 포함 하거나 줄 바꿈 포함) HTML 파서는 코드를 렌더링 할 때 각 공백 시퀀스를 단일 공백으로 줄입니다. 왜 그렇게 많은 공백을 사용합니까? 답은 가독성입니다.</p> + +<p>코드의 보기 좋게 정리되어 있다면 코드에서 무슨 일이 일어나고 있는지 이해하는 것이 더 쉬울 수 있습니다. HTML에는 중첩 된 각 요소가 내부에있는 것보다 두 칸 더 들여 쓰기되어 있습니다. 서식 스타일 (예 : 각 들여 쓰기 수준에 대한 공백 수)을 선택하는 것은 사용자의 몫이지만 서식을 고려해야합니다.</p> + +<h2 id="Entity_references_HTML에_특수_문자_포함">Entity references: HTML에 특수 문자 포함</h2> + +<p>HTML에서 문자 <code><</code>,<code>></code>, <code>"</code>및 <code>&</code>는 특수 문자입니다. 이들은 HTML 구문 자체의 일부입니다. 그럼 어떻게 이러한 특수 문자 중 하나를 내가 사용하고 싶은 텍스트에 포함할까요? 예를 들어, 앰퍼샌드 또는 이하 기호를 텍스트에 사용하고 HTML 코드로 해석되지 않게 하려는 경우와 같이 말입니다.</p> + +<p>표를 참고하여 실습해보세요. 오른쪽의 특별한 코드는 특수 문자를 표현할 때 사용되는 문자 참조 코드입니다. 각 문자 참조는 앰퍼샌드 (&)로 시작하고 세미콜론 (;)으로 끝납니다.</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Literal character</th> + <th scope="col">Character reference equivalent</th> + </tr> + </thead> + <tbody> + <tr> + <td><</td> + <td>&lt;</td> + </tr> + <tr> + <td>></td> + <td>&gt;</td> + </tr> + <tr> + <td>"</td> + <td>&quot;</td> + </tr> + <tr> + <td>'</td> + <td>&apos;</td> + </tr> + <tr> + <td>&</td> + <td>&amp;</td> + </tr> + </tbody> +</table> + +<p>문자 참조에 해당하는 문자는 '&lt;'보다 작거나 '&quot;'에 대한 인용 및 기타 문자 참조와 유사하게 볼 수 있기 때문에 쉽게 기억할 수 있습니다. 엔터티 참조에 대한 자세한 내용은 <a href="http://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references" rel="nofollow">List of XML and HTML character entity references</a> (Wikipedia)을 참조하십시오.</p> + +<p>아래 예시는 두 개의 단락이 있습니다.</p> + +<pre class="brush: html notranslate"><p>In HTML, you define a paragraph using the <p> element.</p> + +<p>In HTML, you define a paragraph using the &lt;p&gt; element.</p></pre> + +<p>아래의 라이브 출력에서 첫 번째 단락이 잘못되었음을 알 수 있습니다. 브라우저는 <p>의 두 번째 인스턴스를 새 단락을 시작하는 것으로 해석합니다. 두 번째 단락에는 문자 참조가있는 꺾쇠 괄호가 있으므로 잘 보입니다.</p> + +<p>{{ EmbedLiveSample('Entity_references_Including_special_characters_in_HTML', 700, 200, "", "", "hide-codepen-jsfiddle") }}</p> + +<div class="note"> +<p><strong>참고</strong>: HTML의 <a href="https://wiki.developer.mozilla.org/ko/docs/Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML#Specifying_your_document's_character_encoding">문자 인코딩이 UTF-8로 설정</a>되어 있기 때문에 최신 브라우저는 실제 기호를 잘 처리하므로 다른 기호에 대해서는 엔티티 참조를 사용할 필요가 없습니다.</p> +</div> + +<h2 id="HTML_주석">HTML 주석</h2> + +<p>HTML에는 코드에 주석을 작성하는 메커니즘이 있습니다. 브라우저는 주석을 무시하여 사용자가 주석을 보이지 않게합니다. 주석의 목적은 코드에 메모를 포함시켜 논리 또는 코딩을 설명 할 수 있도록하는 것입니다. 이것은 코드를 완전히 기억하지 못할 정도로 오랫동안 멀어진 후 코드베이스로 돌아 오는 경우에 매우 유용합니다. 마찬가지로, 다른 사람들이 변경하고 업데이트함에 따라 의견이 매우 중요합니다.</p> + +<p>HTML 주석을 쓰려면 특수 마커 <code><!-</code> 및 <code>-></code>로 주석을 묶습니다. 예를 들면 다음과 같습니다.</p> + +<pre class="brush: html notranslate"><p>I'm not inside a comment</p> + +<!-- <p>I am!</p> --></pre> + +<p>아래에서 볼 수 있듯이 첫 번째 단락만 라이브 출력에 표시됩니다.</p> + +<p>{{ EmbedLiveSample('HTML_comments', 700, 100, "", "", "hide-codepen-jsfiddle") }}</p> + +<h2 id="Summary">Summary</h2> + +<p>HTML 기본 사항을 둘러 보셨기를 바랍니다.</p> + +<p>이 글을 읽고나면 HTML의 모양과 기본 수준에서 작동하는 방식을 이해해야합니다. 또한 몇 가지 요소와 속성을 작성할 수 있어야합니다. 이 모듈의 후속 기사에서는 여기에 소개 된 주제 중 일부에 대해 더 설명하고 언어의 다른 개념을 제시합니다.</p> + +<div class="note"> +<p><strong>참고</strong>: HTML에 대해 더 배우기 시작하면 CSS (Cascading Style Sheets)의 기본 사항을 배우십시오. <a href="https://wiki.developer.mozilla.org/en-US/docs/Learn/CSS">CSS</a>는 웹 페이지의 스타일을 지정하는데 사용되는 언어입니다. (예 : 글꼴 또는 색상 변경 또는 페이지 레이아웃 변경) HTML과 CSS는 곧 발견 될 것입니다.</p> +</div> + +<div>{{NextMenu("Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML", "Learn/HTML/Introduction_to_HTML")}}</div> diff --git a/files/ko/learn/html/introduction_to_html/html_text_fundamentals/index.html b/files/ko/learn/html/introduction_to_html/html_text_fundamentals/index.html new file mode 100644 index 0000000000..9121a02696 --- /dev/null +++ b/files/ko/learn/html/introduction_to_html/html_text_fundamentals/index.html @@ -0,0 +1,654 @@ +--- +title: HTML text fundamentals +slug: Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals +translation_of: Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML", "Learn/HTML/Introduction_to_HTML/Creating_hyperlinks", "Learn/HTML/Introduction_to_HTML")}}</div> + +<p class="summary">HTML의 주요 작업 중 하나는 브라우저가 텍스트를 올바르게 표시 할 수 있도록 텍스트 구조와 의미 (시멘틱({{glossary ( "semantics")}})라고도 함)를 제공하는 것입니다.<br> + 이번 글에서는 {{glossary ( "HTML")}}을 사용하여 제목 및 단락을 추가하고, 단어를 강조하고, 목록을 만드는 등의 방법으로 텍스트 페이지를 구성하는 방법을 설명합니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">선행 학습:</th> + <td><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Getting_started">HTML 시작하기</a>에서 다뤄봤던 HTML의 기초에 익숙해지기.</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>문단, 제목, 목록, 강조 및 인용구를 포함한 구조와 의미를 부여하기 위해 텍스트의 기본 페이지를 표시하는 방법에 대해 배웁니다.</td> + </tr> + </tbody> +</table> + +<h2 id="기본적인_것_제목과_단락">기본적인 것: 제목과 단락</h2> + +<p>대부분의 구조화 된 텍스트는 기사, 신문, 대학 교과서, 잡지 등 무엇을 읽든지 간에 제목과 단락으로 구성됩니다.</p> + +<p><img alt="An example of a newspaper front cover, showing use of a top level heading, subheadings and paragraphs." src="https://mdn.mozillademos.org/files/12371/newspaper_small.jpg" style="display: block; margin: 0px auto;" title="An example of a newspaper front cover, showing use of a top level heading, subheadings and paragraphs."></p> + +<p>구조화된 컨텐츠는 읽는 경험을 더 쉽고 즐겁게 만들어줍니다.</p> + +<p>HTML에서는 각 단락은 {{htmlelement("p")}} 요소 안에 둘러싸여 있어야 합니다. 다음에 나오는 것 처럼 :</p> + +<pre class="brush: html notranslate"><p>I am a paragraph, oh yes I am.</p></pre> + +<p>각 제목도 heading 요소 안에 둘려싸여 있어야 합니다 :</p> + +<pre class="brush: html notranslate"><h1>I am the title of the story.</h1></pre> + +<p>heading 요소는 총 6개가 있습니다— {{htmlelement("h1")}}, {{htmlelement("h2")}}, {{htmlelement("h3")}}, {{htmlelement("h4")}}, {{htmlelement("h5")}}, and {{htmlelement("h6")}}. 각 요소는 문서에서 다른 수준의 내용을 나타냅니다 ; 메인 제목을 <code><h1></code> 으로 나타내고, 소제목을 <code><h2></code> 으로 나타내고, 소제목의 소제목을 <code><h3></code>으로 나타내고 이런 식으로 제목들을 나타냅니다 .</p> + +<h3 id="구조화된_계층을_구현하기">구조화된 계층을 구현하기</h3> + +<p>예를 들어, 한 이야기에서 <h1>은 이야기의 제목을 나타내고 <h2>는 각 장의 제목을 나타내고 <h3>는 각 장의 하위 절을 나타내고 이런 식으로 나타냅니다.</p> + +<pre class="brush: html notranslate"><h1>The Crushing Bore</h1> + +<p>By Chris Mills</p> + +<h2>Chapter 1: The dark night</h2> + +<p>It was a dark night. Somewhere, an owl hooted. The rain lashed down on the ...</p> + +<h2>Chapter 2: The eternal silence</h2> + +<p>Our protagonist could not so much as a whisper out of the shadowy figure ...</p> + +<h3>The specter speaks</h3> + +<p>Several more hours had passed, when all of a sudden the specter sat bolt upright and exclaimed, "Please have mercy on my soul!"</p></pre> + +<p>구조화된 계층이 타당해 보이는 한 연관된 요소들이 정확히 무엇을 나타내는지는 당신에게 달려있습니다. 다만 그러한 구조들을 만들 때 다음 몇 가지의 관례만 기억하면 됩니다:</p> + +<ul> + <li>가급적이면 페이지 당 하나의 <code><h1></code> 만 사용해야 합니다. — <code><h1></code>은 최상위에 있는 표제이며 나머지 다른 표제들은 계층적으로 이것 밑에 위치합니다.</li> + <li>각 표제들을 계층적으로 올바른 순서로 사용해야 함을 명심하세요. <h3>을 하위 표제로 사용하고 그 다음 <h2>를 하위 표제의 하위로 사용하지 마십시오. 이해하기 어려울 뿐더러 이상한 결과를 야기할 수 있습니다.</li> + <li>6개의 Heading을 사용할 수 있지만 꼭 필요한 것이 아니라면 한 페이지에 3개 이상을 사용하지 않도록 하십시오. 많은 목차 레벨을 가진 문서(예를 들어 너무 깊은 heading 계층)는 다루기 힘들고 탐색하기 어려습니다. 이러한 상황에서는 가능하다면 컨텐츠를 여러 페이지로 나누는 것이 바람직합니다.</li> +</ul> + +<h3 id="왜_우리는_구조가_필요할까요">왜 우리는 구조가 필요할까요?</h3> + +<p>이 질문에 대답하기 위해, <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/html-text-formatting/text-start.html">text-start.html</a> — 이 글에서 작동 원리를 보여주는 예시 첫 부분 (맛있는 hummus 레시피)- 을 봅시다. 이후 실습에서 필요하기 때문에 당신의 로컬 저장소에 이 파일의 복사본을 저장해야 합니다. 이 문서의 body는 다양한 컨텐츠 조각들을 가지고 있습니다. 이것들이 Marked up 된 것은 아니지만 줄바꿈으로 구분되어 있습니다. (다음 줄로 가기 위해 Enter/Return이 눌림)</p> + +<p>하지만, 당신이 브라우저에서 문서를 열어보았을 때 당신은 텍스트가 한 덩어리로 뭉쳐있는 것을 볼 것입니다!</p> + +<p><img alt="A webpage that shows a wall of unformatted text, because there are no elements on the page to structure it." src="https://mdn.mozillademos.org/files/14827/Screen%20Shot%202017-03-29%20at%2009.20.35.png" style="display: block; height: 377px; margin: 0px auto; width: 600px;" title="A webpage that shows a wall of unformatted text, because there are no elements on the page to structure it."></p> + +<p>이는 컨텐츠에 구조를 입히는 요소가 없기 때문인데, 그래서 브라우저는 무엇이 heading이고 무엇이 문단인지 알 수 없는 것입니다. 추가로:</p> + +<ul> + <li>웹 페이지를 보는 유저는 필요한 컨텐츠를 빠르게 훑어보는 경향이 있고 자주 heading만 읽기도 합니다. (we usually <a class="external external-icon" href="http://www.nngroup.com/articles/how-long-do-users-stay-on-web-pages/">spend a very short time on a web page</a> 우리는 보통 웹 페이지에서 매우 짧은 시간을 보냅니다.). 몇 초 안에 필요한 어떤 것도 찾지 못하면 그들은 실망하고 다른 곳으로 갈 수도 있습니다.</li> + <li>검색 엔진들은 당신의 페이지 내 heading을 페이지 검색 순위에 영향을 주는 중요한 키워드로 고려해 indexing 합니다. heading이 없다면, 당신의 페이지는 검색 엔진 최적화에 관해서는 형편없게 됩니다. {{glossary("SEO")}} (Search Engine Optimization).</li> + <li>심각한 시각 장애인들은 자주 웹페이지를 읽지 못합니다. 대신 그들은 듣습니다. 이는 <a class="external external-icon" href="http://en.wikipedia.org/wiki/Screen_reader" title="screen readers">screen reader</a> 라고 불리는 소프트웨어를 사용해 이루어집니다. 이 소프트웨어는 텍스트 컨텐츠에 더 빠르게 접근할 수 있는 방안을 제공합니다. 사용된 다양한 기술 중 하나로, 그들은 heading을 읽어줌으로서 문서의 개요를 제공하며 그들의 사용자들이 필요로 하는 정보를 빠르게 찾을 수 있도록 합니다. heading이 없었더라면 그들은 어쩔 수 없이 문서 전체를 읽어야 했을 것입니다. </li> + <li>컨텐츠를 {{glossary("CSS")}}로 꾸미거나, {{glossary("JavaScript")}}로 흥미로운 일을 하게 하기 위해서, 당신은 관련 컨텐츠를 감싸는 요소가 필요합니다. 그렇게 하면 CSS/JavaScript는 효과적으로 그에 적용될 수 있습니다.</li> +</ul> + +<p>그러므로 우리는 컨텐츠를 구조적인 markup에 적용시켜야 합니다.</p> + +<h3 id="활동적인_학습_컨텐츠에_구조_입히기">활동적인 학습: 컨텐츠에 구조 입히기</h3> + +<p>실제 예시에 바로 적용해 봅시다. 아래 예시에서, Input 부분에 있는 raw text에 요소를 더해서 Output 부분에 heading과 두 문단으로 나오도록 해 봅시다. </p> + +<p>실수를 하면 언제든 Reset 버튼을 눌러 리셋할 수 있습니다. 진행 중 막히면, Show solution 버튼을 눌러 답을 볼 수 있습니다.</p> + +<div class="hidden"> +<h6 id="Playable_code">Playable code</h6> + +<pre class="brush: html notranslate"><h2>Input</h2> +<textarea id="code" class="input">My short story + +I am a policewoman and my name is Trish. + +My legs are made of cardboard and I am married to a fish.</textarea> +<h2>Output</h2> +<div class="output"></div> +<div class="controls"> + <input id="reset" type="button" value="Reset" /> + <input id="solution" type="button" value="Show solution" /> +</div> +</pre> + +<pre class="brush: css notranslate">body { + font-family: 'Open Sans Light', Helvetica, Arial, sans-serif; +} + +.input, .output { + width: 90%; + height: 8em; + padding: 10px; + border: 1px solid #0095dd; + overflow: auto; +} + +button { + padding: 10px 10px 10px 0; +} +</pre> + +<pre class="brush: js notranslate">var textarea = document.getElementById("code"); +var reset = document.getElementById("reset"); +var code = textarea.value; +var output = document.querySelector(".output"); +var solution = document.getElementById("solution"); + +function drawOutput() { + output.innerHTML = textarea.value; +} + +reset.addEventListener("click", function() { + textarea.value = code; + drawOutput(); +}); + +solution.addEventListener("click", function() { +textarea.value = '<h1>My short story</h1>\n<p>I am a policewoman and my name is Trish.</p>\n<p>My legs are made of cardboard and I am married to a fish.</p>'; + drawOutput(); +}); + +textarea.addEventListener("input", drawOutput); +window.addEventListener("load", drawOutput); +</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code', 700, 500) }}</p> + +<h3 id="우리는_왜_Semantic을_필요로_할까">우리는 왜 Semantic을 필요로 할까?</h3> + +<p>Semantic(직역 : 의미를 담은, 의미론적인)은 우리 주변 어디에서나 사용됩니다. 우리는 과거의 경험으로부터 일상적인 대상의 기능이 무엇인지 구분합니다. 우리가 어떤 것을 보면 그것의 기능은 무엇일지 알 수 있습니다. 그래서, 예를 들어, 우리가 빨간 신호등을 '멈춤'으로, 초록 신호등을 '출발'로 인식합니다. 잘못된 semantic들이 적용될 경우 상황은 복잡해집니다. (빨간색을 '출발'로 사용하는 나라가 있을까요? 없기를 바랍니다.)</p> + +<p>비슷한 맥락에서, 우리는 정확한 요소를 사용하고 있는지, 우리의 컨텐츠에 정확한 의미, 기능, 모습을 담았는지 확실히 해야 합니다. 이 맥락에서 {{htmlelement("h1")}} 요소 또한 텍스트에 "내 페이지 최상위 heading"의 역할로 감싸는 semantic 요소입니다.</p> + +<pre class="brush: html notranslate"><h1>This is a top level heading</h1> +</pre> + +<p>기본적으로, 브라우저는 이에 큰 사이즈의 폰트를 적용해 heading처럼 보이게 할 것입니다. (비록 당신이 CSS를 사용해 원하는 어떤 모습으로도 스타일 할 수 있지만 말입니다.) 더 중요하게, 이것의 의미론적인 가치는 다양한 방식으로 사용될 것입니다. 예를 들어 검색 엔진이나 screen reader들에서 말이죠. (위에서 서술한 것처럼.)</p> + +<p>반면에, 당신은 어떤 요소도 최상위 heading처럼 <em>보이게 </em>할 수 있습니다. 다음을 고려해 봅시다:</p> + +<pre class="brush: html notranslate"><span style="font-size: 32px; margin: 21px 0;">Is this a top level heading?</span></pre> + +<p>이것은 {{htmlelement("span")}} 요소입니다. 의미가 없죠. 당신은 컨텐츠에 추가적인 의미를 더하지 않고 CSS 를 적용하고 싶을 때 (혹은 JavaScript를 적용해 무언가를 하고 싶을 때) 이것을 사용합니다. (이것들에 대해서는 코스 뒤에서 더 알게 될겁니다.) 우리는 이것에 CSS를 더해 최상위 heading처럼 보이게 했지만, 이것이 semantic(의미론적인) 가치는 없기 때문에, 위에서 서술된 추가적인 이득들은 얻지 못할 것입니다. 작업에 관계있는 HTML 요소를 사용하는 것이 좋은 생각입니다.</p> + +<h2 id="Lists">Lists</h2> + +<p>이제 List에 집중해 봅시다. List는 삶의 모든 부분에 있습니다 - 쇼핑 리스트에서 당신이 매일 집에 오기 위해 무의식적으로 따르는 지시들의 리스트까지, 이 튜토리얼에서 당신이 따르는 지시들의 리스트까지! 웹에서도 List는 어디에나 있습니다. 그리고 우리는 고려해야 할 3개의 종류를 가지고 있습니다.</p> + +<h3 id="Unordered_순서_없음">Unordered (순서 없음)</h3> + +<p>정렬되지 않은 목록은 항목의 순서가 중요하지 않은 항목 목록을 표시하는 데 사용됩니다</p> + +<p>- 쇼핑 리스트 항목으로 예를 들어보자</p> + +<pre class="notranslate">milk +eggs +bread +hummus</pre> + +<p>순서 없는 리스트를 정렬하기 위해 {{htmlelement("ul")}} element 를 이용해 감싸줍니다.</p> + +<p>모든 리스트 아이템:</p> + +<pre class="brush: html notranslate"><ul> +milk +eggs +bread +hummus +</ul></pre> + +<p>마지막으로 그안의 리스트 항목들을 {{htmlelement("li")}} (list item) 태그로 감싸줍니다.</p> + +<pre class="brush: html notranslate"><ul> + <li>milk</li> + <li>eggs</li> + <li>bread</li> + <li>hummus</li> +</ul></pre> + +<h4 id="활동적인_학습_순서_없는_리스트_만들기">활동적인 학습 : 순서 없는 리스트 만들기</h4> + +<p>HTML 순서 없는(unordered) 리스트를 만들기 위해 아래에 있는 샘플을 편집해보자.</p> + +<div class="hidden"> +<h6 id="Playable_code_2">Playable code</h6> + +<pre class="brush: html notranslate"><h2>Input</h2> +<textarea id="code" class="input">milk +eggs +bread +hummus</textarea> +<h2>Output</h2> +<div class="output"></div> +<div class="controls"> + <input id="reset" type="button" value="Reset" /> + <input id="solution" type="button" value="Show solution" /> +</div> +</pre> + +<pre class="brush: css notranslate">body { + font-family: 'Open Sans Light', Helvetica, Arial, sans-serif; +} + +.input, .output { + width: 90%; + height: 6em; + padding: 10px; + border: 1px solid #0095dd; + overflow: auto; +} + +button { + padding: 10px 10px 10px 0; +} +</pre> + +<pre class="brush: js notranslate">var textarea = document.getElementById("code"); +var reset = document.getElementById("reset"); +var code = textarea.value; +var output = document.querySelector(".output"); +var solution = document.getElementById("solution"); + +function drawOutput() { + output.innerHTML = textarea.value; +} + +reset.addEventListener("click", function() { + textarea.value = code; + drawOutput(); +}); + +solution.addEventListener("click", function() { +textarea.value = '<ul>\n<li>milk</li>\n<li>eggs</li>\n<li>bread</li>\n<li>hummus</li>\n</ul>'; + drawOutput(); +}); + +textarea.addEventListener("input", drawOutput); +window.addEventListener("load", drawOutput); +</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code_2', 700, 400) }}</p> + +<h3 id="Ordered_순서_있음">Ordered (순서 있음)</h3> + +<p>순서 있는 리스트는 항목의 순서가 중요한 목록 입니다. 순서를 꼭 정해주세요</p> + +<p>예제:</p> + +<pre class="notranslate">Drive to the end of the road +Turn right +Go straight across the first two roundabouts +Turn left at the third roundabout +The school is on your right, 300 meters up the road</pre> + +<p>{{htmlelement("ul")}}태그가 아닌 {{htmlelement("ol")}} 태그로 감싸는것을 제외하고는 마크업 구조는 순서가 없는 리스트와 동일하다.</p> + +<pre class="brush: html notranslate"><ol> + <li>Drive to the end of the road</li> + <li>Turn right</li> + <li>Go straight across the first two roundabouts</li> + <li>Turn left at the third roundabout</li> + <li>The school is on your right, 300 meters up the road</li> +</ol></pre> + +<h4 id="활동적인_학습_순서가_있는_리스트를_만들어보자">활동적인 학습: 순서가 있는 리스트를 만들어보자</h4> + +<p>HTML 순서가 있는(ordered) 리스트를 만들기 위해 아래에 있는 샘플을 편집해보자.</p> + +<div class="hidden"> +<h6 id="Playable_code_3">Playable code</h6> + +<pre class="brush: html notranslate"><h2>Input</h2> +<textarea id="code" class="input">Drive to the end of the road +Turn right +Go straight across the first two roundabouts +Turn left at the third roundabout +The school is on your right, 300 meters up the road</textarea> +<h2>Output</h2> +<div class="output"></div> +<div class="controls"> + <input id="reset" type="button" value="Reset" /> + <input id="solution" type="button" value="Show solution" /> +</div> +</pre> + +<pre class="brush: css notranslate">body { + font-family: 'Open Sans Light', Helvetica, Arial, sans-serif; +} + +.input, .output { + width: 90%; + height: 8em; + padding: 10px; + border: 1px solid #0095dd; + overflow: auto; +} + +button { + padding: 10px 10px 10px 0; +} +</pre> + +<pre class="brush: js notranslate">var textarea = document.getElementById("code"); +var reset = document.getElementById("reset"); +var code = textarea.value; +var output = document.querySelector(".output"); +var solution = document.getElementById("solution"); + +function drawOutput() { + output.innerHTML = textarea.value; +} + +reset.addEventListener("click", function() { + textarea.value = code; + drawOutput(); +}); + +solution.addEventListener("click", function() { +textarea.value = '<ol>\n<li>Drive to the end of the road</li>\n<li>Turn right</li>\n<li>Go straight across the first two roundabouts</li>\n<li>Turn left at the third roundabout</li>\n<li>The school is on your right, 300 meters up the road</li>\n</ol>'; + drawOutput(); +}); + +textarea.addEventListener("input", drawOutput); +window.addEventListener("load", drawOutput); +</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code_3', 700, 500) }}</p> + +<h3 id="활동적인_학습_우리의_레시피_페이지를_만들어보자">활동적인 학습: 우리의 레시피 페이지를 만들어보자</h3> + +<p>이제 우리는 레시피 페이지 예시를 만드는 데 필요한 모든 정보를 가지고 있습니다. text-start.html 시작 파일을 저장해 그곳에서 작업을 하셔도 좋고, 아래에 있는 편집 가능한 샘플에서 작업을 할 수도 있습니다. 따로 파일을 생성해서 작업을 하면 언제든지 편집이 가능합니다. 아래 샘플에서 작업을 하면 다음에 이 페이지를 열 때 작업 기록이 사라져 있을 것입니다. 이 두가지 방법은 장점과 단점 모두를 지니고 있습니다.</p> + +<div class="hidden"> +<h6 id="Playable_code_4">Playable code</h6> + +<pre class="brush: html notranslate"><h2>Input</h2> +<textarea id="code" class="input">Quick hummus recipe + + This recipe makes quick, tasty hummus, with no messing. It has been adapted from a number of different recipes that I have read over the years. + + Hummus is a delicious thick paste used heavily in Greek and Middle Eastern dishes. It is very tasty with salad, grilled meats and pitta breads. + + Ingredients + + 1 can (400g) of chick peas (garbanzo beans) + 175g of tahini + 6 sundried tomatoes + Half a red pepper + A pinch of cayenne pepper + 1 clove of garlic + A dash of olive oil + + Instructions + + Remove the skin from the garlic, and chop coarsely + Remove all the seeds and stalk from the pepper, and chop coarsely + Add all the ingredients into a food processor + Process all the ingredients into a paste. + If you want a coarse "chunky" hummus, process it for a short time + If you want a smooth hummus, process it for a longer time + + For a different flavour, you could try blending in a small measure of lemon and coriander, chili pepper, lime and chipotle, harissa and mint, or spinach and feta cheese. Experiment and see what works for you. + + Storage + + Refrigerate the finished hummus in a sealed container. You should be able to use it for about a week after you've made it. If it starts to become fizzy, you should definitely discard it. + + Hummus is suitable for freezing; you should thaw it and use it within a couple of months.</textarea> +<h2>Output</h2> +<div class="output"></div> +<div class="controls"> + <input id="reset" type="button" value="Reset" /> + <input id="solution" type="button" value="Show solution" /> +</div> +</pre> + +<pre class="brush: css notranslate">body { + font-family: 'Open Sans Light', Helvetica, Arial, sans-serif; +} + +.input, .output { + width: 90%; + height: 8em; + padding: 10px; + border: 1px solid #0095dd; + overflow: auto; +} + +button { + padding: 10px 10px 10px 0; +} +</pre> + +<pre class="brush: js notranslate">var textarea = document.getElementById("code"); +var reset = document.getElementById("reset"); +var code = textarea.value; +var output = document.querySelector(".output"); +var solution = document.getElementById("solution"); + +function drawOutput() { + output.innerHTML = textarea.value; +} + +reset.addEventListener("click", function() { + textarea.value = code; + drawOutput(); +}); + +solution.addEventListener("click", function() { + textarea.value = '<h1>Quick hummous recipe</h1>\n\n<p>This recipe makes quick, tasty hummus, with no messing. It has been adapted from a number of different recipes that I have read over the years.</p>\n\n<p>Hummus is a delicious thick paste used heavily in Greek and Middle Eastern dishes. It is very tasty with salad, grilled meats and pitta breads.</p>\n\n<h2>Ingredients</h2>\n\n<ul>\n<li>1 can (400g) of chick peas (garbanzo beans)</li>\n<li>175g of tahini</li>\n<li>6 sundried tomatoes</li>\n<li>Half a red pepper</li>\n<li>A pinch of cayenne pepper</li>\n<li>1 clove of garlic</li>\n<li>A dash of olive oil</li>\n</ul>\n\n<h2>Instructions</h2>\n\n<ol>\n<li>Remove the skin from the garlic, and chop coarsely.</li>\n<li>Remove all the seeds and stalk from the pepper, and chop coarsely.</li>\n<li>Add all the ingredients into a food processor.</li>\n<li>Process all the ingredients into a paste.</li>\n<li>If you want a coarse "chunky" hummus, process it for a short time.</li>\n<li>If you want a smooth hummus, process it for a longer time.</li>\n</ol>\n\n<p>For a different flavour, you could try blending in a small measure of lemon and coriander, chili pepper, lime and chipotle, harissa and mint, or spinach and feta cheese. Experiment and see what works for you.</p>\n\n<h2>Storage</h2>\n\n<p>Refrigerate the finished hummus in a sealed container. You should be able to use it for about a week after you\'ve made it. If it starts to become fizzy, you should definitely discard it.</p>\n\n<p>Hummus is suitable for freezing; you should thaw it and use it within a couple of months.</p>'; + drawOutput(); +}); + +textarea.addEventListener("input", drawOutput); + +window.addEventListener("load", drawOutput); +</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code_4', 700, 500) }}</p> + +<p>위의 문제를 해결하는데 어려움을 겪고있다면, <em>Show solution</em> 버튼을 클릭하여 해답을 확인하거나, GitHub 레포지토리에 존재하는 <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/html-text-formatting/text-complete.html">text-complete.html</a> 파일을 확인해 주시길 바랍니다.</p> + +<h3 id="리스트_내부의_리스트Nesting_lists">리스트 내부의 리스트(Nesting lists)</h3> + +<p>하나의 리스트 내부에 다른 리스트를 추가하는 것은 아무런 문제가 없습니다. 당신이 최상위 리스트 아이템의 내부에 다른 리스트를 추가하고 싶다면, 하단의 예제들 중 두번째 예제를 확인해주세요.</p> + +<pre class="brush: html notranslate"><ol> + <li>Remove the skin from the garlic, and chop coarsely.</li> + <li>Remove all the seeds and stalk from the pepper, and chop coarsely.</li> + <li>Add all the ingredients into a food processor.</li> + <li>Process all the ingredients into a paste.</li> + <li>If you want a coarse "chunky" hummus, process it for a short time.</li> + <li>If you want a smooth hummus, process it for a longer time.</li> +</ol></pre> + +<p>마지막 두개의 리스트 아이템은 <code>Process all the ingredients into a paste.</code>와 밀접한 관계가 있는 내용입니다. 그러므로 두개의 리스트 아이템은 <code>Process all the ingredients into a paste.</code>의 내부에 중첩되어 나타나는 것이 더 좋을 것입니다. 하단과 같은 방법을 사용해서 말이죠.</p> + +<pre class="brush: html notranslate"><ol> + <li>Remove the skin from the garlic, and chop coarsely.</li> + <li>Remove all the seeds and stalk from the pepper, and chop coarsely.</li> + <li>Add all the ingredients into a food processor.</li> + <li>Process all the ingredients into a paste. + <ul> + <li>If you want a coarse "chunky" hummus, process it for a short time.</li> + <li>If you want a smooth hummus, process it for a longer time.</li> + </ul> + </li> +</ol></pre> + +<p>첫번째의 예제로 돌아가, 두번째의 예제처럼 변경하는 연습을 해보시길 바랍니다.</p> + +<h2 id="중요와_강조">중요와 강조</h2> + +<p>우리는 문장의 의미를 바꾸거나 특정한 단어를 강조하기위해 종종 일반적인 방법과 다르게 표현하기도 합니다. HTML은 그런 경우를 표시할 수 있도록 다양한 의미 요소를 제공하며, 이 섹션에서는 가장 일반적인 몇 가지 요소를 살펴보기로 합니다.</p> + +<h3 id="중요Emphasis">중요(Emphasis)</h3> + +<p>우리는 말을 하면서 특정 단어를 강세를 두고 발음하는 방법으로 의미를 다르게 표현합니다. 마찬가지로, 글에서는 단어에 강세를 두기 위해 이탤릭체로 표현하는 경향이 있습니다. 예를 들어, 다음 두 문장은 다른 의미를 가집니다. </p> + +<p>I am glad you weren't late.</p> + +<p>I am <em>glad</em> you weren't <em>late</em>.</p> + +<p>첫 문장은 상대가 늦지 않은 것에 대해 진심으로 안도하는 것처럼 들립니다. 이와는 대조적으로, 두 번째 문장은 상대가 조금 늦게 도착한 것에대해 비꼬거나 짜증을 표현하는 것처럼 들립니다.</p> + +<p>HTML에서는 이러한 경우를 표시하기 위해 {{htmlelement("em")}} (emphasis) 요소를 사용합니다. 문서를 더 흥미롭게 읽게 될 뿐만 아니라, 화면판독기에 인식되면 다른 톤의 목소리로 표현됩니다. 브라우저에서는 기본적으로 이탤릭체로 스타일을 지정하지만, 단지 이탤릭체로 스타일링하기 위해 이 태그를 사용하는 것은 지양합니다. 스타일링을 위해서는{{htmlelement("span")}} 요소에 약간의 CSS를 더하거나 {{htmlelement("i")}}요소를 사용할 수 있습니다.(아래 참조).</p> + +<pre class="brush: html notranslate"><p>I am <em>glad</em> you weren't <em>late</em>.</p></pre> + +<h3 id="강조Strong_importance">강조(Strong importance)</h3> + +<p>우리는 중요한 단어를 강조하기 위해 강세를 두고 말하거나 글자를 두껍게 표현합니다. 예를들면,</p> + +<p>This liquid is <strong>highly toxic</strong>.</p> + +<p>I am counting on you. <strong>Do not</strong> be late!</p> + +<p>HTML에서는 이러한 경우를 표시하기 위해 {{htmlelement("strong")}} (strong importance)요소를 사용합니다. 문서를 더 유용하게 만드는 것뿐만 아니라, 화면판독기에 인식되면 다른 톤의 목소리로 표현됩니다. 브라우저에서는 기본적으로 굵은 텍스트로 스타일을 지정하지만, 단지 굵게 스타일링하기 위해 이 태그를 사용하는 것은 지양합니다. 스타일링을 위해서는 {{htmlelement("span")}} 요소에 약간의 CSS를 더하거나 {{htmlelement("b")}} 요소를 사용할 수 있습니다.(아래 참조).</p> + +<pre class="brush: html notranslate"><p>This liquid is <strong>highly toxic</strong>.</p> + +<p>I am counting on you. <strong>Do not</strong> be late!</p></pre> + +<p>원한다면 각각의 태그가 서로의 안에 위치할 수 있습니다.</p> + +<pre class="brush: html notranslate"><p>This liquid is <strong>highly toxic</strong> — +if you drink it, <strong>you may <em>die</em></strong>.</p></pre> + +<h3 id="Active_learning_Lets_be_important!">Active learning: Let's be important!</h3> + +<p>이 Active Learning 섹션에서는 편집 가능한 예시를 제공하였습니다. 이 안에서 여러분이 필요하다고 생각되는 단어에 강조와 중요성을 더해보며 연습할 수 있기를 바랍니다.</p> + +<div class="hidden"> +<h6 id="Playable_code_5">Playable code</h6> + +<pre class="brush: html notranslate"><h2>Input</h2> +<textarea id="code" class="input"><h1>Important notice</h1> + +<p>On Sunday January 9th 2010, a gang of goths were +spotted stealing several garden gnomes from a shopping +center in downtown Milwaukee. They were all wearing green +jumpsuits and silly hats, and seemed to be having a whale +of a time. If anyone has any information about this +incident, please contact the police now.</p></textarea> +<h2>Output</h2> +<div class="output"></div> +<div class="controls"> + <input id="reset" type="button" value="Reset" /> + <input id="solution" type="button" value="Show suggestion" /> +</div> +</pre> + +<pre class="brush: css notranslate">body { + font-family: 'Open Sans Light', Helvetica, Arial, sans-serif; +} + +.input, .output { + width: 90%; + height: 8em; + padding: 10px; + border: 1px solid #0095dd; + overflow: auto; +} + +button { + padding: 10px 10px 10px 0; +} +</pre> + +<pre class="brush: js notranslate">var textarea = document.getElementById("code"); +var reset = document.getElementById("reset"); +var code = textarea.value; +var output = document.querySelector(".output"); +var solution = document.getElementById("solution"); + +function drawOutput() { + output.innerHTML = textarea.value; +} + +reset.addEventListener("click", function() { + textarea.value = code; + drawOutput(); +}); + +solution.addEventListener("click", function() { + textarea.value = '<h1>Important notice</h1>\n<p>On <strong>Sunday January 9th 2010</strong>, a gang of <em>goths</em> were spotted stealing <strong><em>several</em> garden gnomes</strong> from a shopping center in downtown <strong>Milwaukee</strong>. They were all wearing <em>green jumpsuits</em> and <em>silly hats</em>, and seemed to be having a whale of a time. If anyone has <strong>any</strong> information about this incident, please contact the police <strong>now</strong>.</p>'; + drawOutput(); +}); + +textarea.addEventListener("input", drawOutput); +window.addEventListener("load", drawOutput); +</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code_5', 700, 500) }}</p> + +<h3 id="Italic_bold_underline...">Italic, bold, underline...</h3> + +<p>우리가 지금까지 얘기했던 요소들은 관련된 의미들을 명확히 구분했습니다. {{htmlelement("b")}}, {{htmlelement("i")}}, {{htmlelement("u")}}의 상황들은 좀 복잡하죠. 이 요소들은 CSS가 형편없이 지원되거나 완전히 지원되지 않는 경우에 이탤릭체 또는 밑줄 등을 표현할 수 있도록 고안되었습니다. 의미론적이 아닌 표현에만 영향을 주는 이와 같은 요소들은 <strong>현재적 요소</strong>로 알려져 있으며, 더 이상 사용되어서는 안됩니다. 앞에서 살펴본 바와 같이 의미론은 접근성, SEO 등에 매우 중요하기 때문이죠.</p> + +<p>HTML5 에서는 <code><b></code>, <code><i>,</code> <code><u></code> 를 조금 혼란스럽긴 하지만 새로운 의미론적 역할로 재정립하였습니다.</p> + +<p>가장 좋은 경험법칙: 적합한 요소가 더 없다면, 과거로부터 줄곧 굵거나 이탤릭체를 쓰거나 밑줄을 치는 방법으로 표현했던 의미를 전달하기 위해 <code><b></code>, <code><i></code>, <code><u></code> 를 사용하는 것이 적절할 것 같다. 그러나 늘 접근성에 관해 염두하는 것은 항상 중요하다. 이탤릭체의 개념은 스크린리더를 사용하는 사람이나 라틴 문자체계 이외의 사용자에게는 별로 도움이 되지 않는다.</p> + +<ul> + <li>{{HTMLElement('i')}} 요소는 과거로부터 줄곧 기울임꼴로 전달되는 의미를 전달하기 위해 사용된다. 외래어, 분류학 명칭, 전문 용어, 생각...</li> + <li>{{HTMLElement('b')}} 요소는 과거로부터 줄곧 굵은 글씨로 전달되는 의미를 전달할 때 사용한다. 주요 단어, 제품 이름, 주요 문장...</li> + <li>{{HTMLElement('u')}} 요소는 과거로부터 줄곧 밑줄을 치는 것으로 전달되는 의미를 전달할 떄 사용한다. 적절한 이름, 잘못된 철자...</li> +</ul> + +<div class="note"> +<p>밑줄에 대한 위험성 중 하나: <strong>사람들은 밑줄을 하이퍼링크와 강하게 연관시킨다. </strong>따라서 웹에서는 링크에만 밑줄을 긋는 것이 가장 좋다. 의미론적으로 적합한 경우 <code><u></code> 요소를 사용하되, CSS를 사용하여 기본 밑줄을 웹에서 더 적합하게 변경할 수 있는지 고려한다. 그것이 어떻게 이루어질 수 있는지는 아래의 예에서 확인할 수 있다.</p> +</div> + +<pre class="brush: html notranslate"><!-- scientific names --> +<p> + The Ruby-throated Hummingbird (<i>Archilochus colubris</i>) + is the most common hummingbird in Eastern North America. +</p> + +<!-- foreign words --> +<p> + The menu was a sea of exotic words like <i lang="uk-latn">vatrushka</i>, + <i lang="id">nasi goreng</i> and <i lang="fr">soupe à l'oignon</i>. +</p> + +<!-- a known misspelling --> +<p> + Someday I'll learn how to <u>spel</u> better. +</p> + +<!-- Highlight keywords in a set of instructions --> +<ol> + <li> + <b>Slice</b> two pieces of bread off the loaf. + </li> + <li> + <b>Insert</b> a tomato slice and a leaf of + lettuce between the slices of bread. + </li> +</ol></pre> + +<h2 id="요약">요약</h2> + +<p>일단 이게 다에요! 이 글을 통해 여러분은 HTML에서 텍스트를 표현하기 시작하는 방법에 대해 좋은 아이디어를 얻었고, 이 영역에서 가장 중요한 몇가지 요소들을 알게되었습니다. 이 코스에에서 다룰 의미론적 요소는 훨씬 더 많으며 <a href="https://wiki.developer.mozilla.org/en-US/docs/Learn/HTML/Introduction_to_HTML/Advanced_text_formatting">Advanced text formatting</a> 를 통해 더 많이 살펴볼 수 있습니다. 다음 글에서는 웹에서 가장 중요한 요소인 <a href="https://wiki.developer.mozilla.org/en-US/docs/Learn/HTML/Introduction_to_HTML/Creating_hyperlinks">하이퍼링크를 만드는 방법</a>에 대해 자세히 알아보도록 합시다.</p> + +<p>{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML", "Learn/HTML/Introduction_to_HTML/Creating_hyperlinks", "Learn/HTML/Introduction_to_HTML")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Getting_started">Getting started with HTML</a></li> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML">What’s in the head? Metadata in HTML</a></li> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals">HTML text fundamentals</a></li> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Creating_hyperlinks">Creating hyperlinks</a></li> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Advanced_text_formatting">Advanced text formatting</a></li> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Document_and_website_structure">Document and website structure</a></li> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Debugging_HTML">Debugging HTML</a></li> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Marking_up_a_letter">Marking up a letter</a></li> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Structuring_a_page_of_content">Structuring a page of content</a></li> +</ul> diff --git a/files/ko/learn/html/introduction_to_html/index.html b/files/ko/learn/html/introduction_to_html/index.html new file mode 100644 index 0000000000..7566119e6e --- /dev/null +++ b/files/ko/learn/html/introduction_to_html/index.html @@ -0,0 +1,59 @@ +--- +title: HTML 소개 +slug: Learn/HTML/Introduction_to_HTML +tags: + - CodingScripting + - HTML + - Landing +translation_of: Learn/HTML/Introduction_to_HTML +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">{{glossary("HTML")}}은 문서의 특정 텍스트 영역이 문단인지 목록인지 표의 일부인지 구분 할 수 있도록 의미를 부여하고, 헤더인지, 콘텐츠 컬럼인지, 네비게이션 메뉴인지 알수 있도록 논리적인 영역으로 구조화 하고, 이미지와 비디오 같은 콘텐츠를 삽입할 수 있게 해주는 요소들로 구성된 지극히 간단한 언어입니다. 이번 과정은 이 두 가지 주제에 대한 소개와 HTML을 이해하기 위해 알아야 하는 기본 개념과 문법을 설명합니다.</p> + +<h2 id="전제_조건">전제 조건</h2> + +<p>이번 과정을 시작하기 전에, HTML에 대한 사전 지식은 필요하지 않습니다만, 기본적으로 컴퓨터 사용에 친숙해야 하고, 웹사이트의 콘텐츠를 탐색하는 정도의 웹을 사용할 줄 알아야 합니다. <a href="https://developer.mozilla.org/ko/docs/Learn/Getting_started_with_the_web/Installing_basic_software">기본 소프트웨어 설치</a>에 있는 기본적인 작업 환경이 구축되어 있어야 하고, <a href="https://developer.mozilla.org/ko/docs/Learn/Getting_started_with_the_web/Dealing_with_files">파일 다루기</a>에 있는 파일을 생성하고 관리하는 방법을 이해하고 있어야 합니다. 이 두가지 내용은 <a href="https://developer.mozilla.org/ko/docs/Learn/Getting_started_with_the_web">웹 시작하기</a>를 위한 초급 과정입니다.</p> + +<div class="note"> +<p><span style="font-size: 14px;"><strong>노트</strong></span>: 혹시, 파일을 생성하기 힘든 컴퓨터/테블릿 혹은 다른 기기에서 작업한다면, <a href="http://jsbin.com/">JSBin</a> 이나 <a href="https://thimble.mozilla.org/">Thimble</a> 같은 온라인 코딩 프로그램을 이용하여 대부분의 코드 예제를 작성해 볼 수 있습니다.</p> +</div> + +<h2 id="안내서">안내서</h2> + +<p>이 과정은 HTML의 모든 기초 이론을 학습하고, 몇몇 기법을 실습해 볼 수 있는 충분한 기회를 제공합니다. 아래와 같은 내용을 담고 있습니다.</p> + +<dl> + <dt><a href="/ko/docs/Learn/HTML/Introduction_to_HTML/Getting_started">HTML 시작하기</a></dt> + <dd>HTML을 시작하기 위한 초급 내용을 다룹니다. 요소, 속성을 정의하고, 한번쯤은 들어봤을지도 모르는 중요한 용어들을 알아보고 어디에 사용되는지 살펴봅니다. 또, HTML 요소를 구조화 하는 방법, 일반적인 HTML 페이지가 어떻게 구조화되는지를 알아보고, 언어의 중요한 기본 특징에 대해 설명합니다. 그러면서, 여러분들이 흥미를 가질 수 있도록 HTML 코드를 직접 작성해 보도록 하겠습니다.</dd> + <dt><a href="/ko/docs/Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML">head 안에는 무엇이 있나? HTML 메타 데이터</a></dt> + <dd>HTML 문서의 헤드는 페이지가 로딩될 때 웹 브라우저에는 보이지 않는 부분입니다. 페이지의 {{htmlelement("title")}}, (HTML 콘텐츠에 스타일을 적용하고 싶다면) {{glossary("CSS")}} 링크, 파비콘 링크, 그리고 메타데이터(문서의 작성자, 문서를 설명하기 위한 중요한 키워드와 같은 HTML에 대한 정보)와 같은 정보를 담고 있습니다.</dd> + <dt><a href="/ko/docs/Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals">HTML 텍스트 기본</a></dt> + <dd>HTML을 사용하는 주요 목적 중의 하나는 텍스트에 의미를 부여(<strong>시맨틱</strong>)하는 것인데, 그렇게 하면 브라우저는 화면에 어떻게 노출되어야 하는지 명확하게 알 수 있습니다. 이 글에서는 HTML을 이용하여 글의 제목과 문단의 구조에서 텍스트를 분리해 보고, 단어에 강조/중요도를 부여해보고, 리스트 만드는 법 등을 살펴 보겠습니다.</dd> + <dt><a href="/ko/docs/Learn/HTML/Introduction_to_HTML/Creating_hyperlinks">하이퍼링크 만들기</a></dt> + <dd>하이퍼링크는 웹을 웹(web, 거미줄, 연결을 의미)으로 만들어주는 것이기 때문에 굉장히 중요합니다. 이 글에서는 링크를 만드는데 필요한 문법을 설명하고, 링크의 사례들을 논의해 봅니다.</dd> + <dt><a href="/ko/docs/Learn/HTML/Introduction_to_HTML/Advanced_text_formatting">텍스트 조작 고급기법</a></dt> + <dd>HTML에는 텍스트를 조작하기 위한 많은 요소들이 있습니다. <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals">이</a> 글에는 다 담을 수는 없습니다. 이 글에서는 잘 알려지진 않았지만 알아두면 굉장히 유용한 요소들을 살펴보겠습니다. 인용구, 설명 목록, 소스 코드 혹은 관련 텍스트, 위첨자, 아래첨자, 연락 정보 등을 마크업 하는 방법을 알아보겠습니다.</dd> + <dt><a href="/ko/docs/Learn/HTML/Introduction_to_HTML/Document_and_website_structure">문서와 웹사이트 구조</a></dt> + <dd>‘문단’이나 ‘이미지’와 같은 페이지의 부분을 정의하는 것처럼, HTML은 ‘헤더’, ‘네비게이션 메뉴’, ‘주요 내용 컬럼’과 같은 웹사이트의 영역을 정의하는데도 사용됩니다. 이 글에서는 기본 웹사이트 구조를 설계하는 법을 살펴보고, 이 구조를 표현하기 위해 HTML로 직접 작성해 보겠습니다.</dd> + <dt><a href="/ko/docs/Learn/HTML/Introduction_to_HTML/Debugging_HTML">HTML 디버깅</a></dt> + <dd>HTML 작성은 잘 되었는데, 무언가 잘못되었고, 작업을 할 수 없다면 코드에서 에러가 발생하는 부분은 어디일까요? 이 글은 이런 상황에 도움을 줄 수 있는 도구들을 소개합니다.</dd> +</dl> + +<h2 id="평가">평가</h2> + +<p>다음의 평가들은 위의 가이드에 있는 HTML 기본을 얼마나 이해하고 있는지 테스트 합니다.</p> + +<dl> + <dt><a href="/ko/docs/Learn/HTML/Introduction_to_HTML/Marking_up_a_letter">마크업</a></dt> + <dd>우리는 모두 편지 쓰는 법을 금방 배우게 됩니다. 텍스트를 꾸미고 조작하는 것을 테스트 해볼 수 있는 유용한 예제들이 있습니다. 여러분이 마크업 하는 것을 평가합니다.</dd> + <dt><a href="/ko/docs/Learn/HTML/Introduction_to_HTML/Structuring_a_page_of_content">페이지 콘텐츠 구조화</a></dt> + <dd>이 평가는 헤더, 푸터, 네비게이션 메뉴, 주요 콘텐츠, 사이드바를 담고 있는 간단한 웹 페이지의 구조를 HTML로 작성하는 능력을 테스트합니다.</dd> +</dl> + +<h2 id="같이_보기">같이 보기</h2> + +<dl> + <dt><a href="https://teach.mozilla.org/activities/web-lit-basics/">웹 지식 기본 1</a></dt> + <dd>HTML 소개 과정에서 논의된 많은 기법들을 살펴보고 테스트 해볼 수 있는 모질라 재단 과정이 있습니다. 학습자들은 이 여섯 가지의 과정에서 글을 읽고, 글을 작성하고, 참석하는데 친숙해 질 것입니다. 만들어 보고 협업하면서 탄탄한 웹의 토대를 찾아보세요.</dd> +</dl> diff --git a/files/ko/learn/html/introduction_to_html/marking_up_a_letter/index.html b/files/ko/learn/html/introduction_to_html/marking_up_a_letter/index.html new file mode 100644 index 0000000000..5d451b0d4e --- /dev/null +++ b/files/ko/learn/html/introduction_to_html/marking_up_a_letter/index.html @@ -0,0 +1,102 @@ +--- +title: Marking up a letter +slug: Learn/HTML/Introduction_to_HTML/Marking_up_a_letter +translation_of: Learn/HTML/Introduction_to_HTML/Marking_up_a_letter +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/Debugging_HTML", "Learn/HTML/Introduction_to_HTML/Structuring_a_page_of_content", "Learn/HTML/Introduction_to_HTML")}}</div> + +<div></div> + +<div>우리 모두 글자를 쓸 줄 압니다. 이제 글을 포멧팅하는 방법을 익혀 보도록 합니다. 이 장에서는 주어진 글을 HTML 기본/혹은 고급 텍스트 포멧팅 방식에 맞춰 다듬는 연습을 할 예정입니다. 예를 들어, 하이퍼링크라든지 <head> 컨텐츠 등을 말이지요.</div> + +<div></div> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">선수 학습:</th> + <td> + <p>이 장에 들어서기에 앞서 필요한 선수 학습들에는 <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Getting_started">Getting started with HTML</a>, <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML">What's in the head? Metadata in HTML</a>, <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals">HTML text fundamentals</a>, <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Creating_hyperlinks">Creating hyperlinks</a>, <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Advanced_text_formatting">Advanced text formatting</a> 등이 있습니다.</p> + </td> + </tr> + <tr> + <th scope="row">이 장에서 배워요:</th> + <td> + <p>HTML 기본/고급 텍스트 포멧팅 방법, 하이퍼링크, HTML <head> 부분에 무엇이 들어가는지에 대해 알아 보아요.</p> + </td> + </tr> + </tbody> +</table> + +<h2 id="시작하기에_앞서">시작하기에 앞서</h2> + +<p>프로젝트를 시작하기 위해서는 두 가지가 필요합니다. <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/marking-up-a-letter-start/letter-text.txt">raw text you need to mark up</a>와 <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/marking-up-a-letter-start/css.txt">CSS you need to include</a>입니다. 텍스트 편집기를 이용해 .html 파일을 만들거나 사이트 - <a class="external external-icon" href="http://jsbin.com/">JSBin</a> 이나 <a class="external external-icon" href="https://thimble.mozilla.org/">Thimble</a> 를 이용하여 프로젝트를 할 수도 있습니다.</p> + +<h2 id="프로젝트_요약">프로젝트 요약</h2> + +<p>이 프로젝트에서 여러분은 대학 인트라넷에 호스팅 될 문서를 마크업 하게 될 겁니다. 이 문서는 미래 해당 대학에서 박사학위를 공부하려는 이들이 보내 온 질문에 대한 연구원들의 답변입니다. </p> + +<p><strong>블록/ 구조적인 시맨틱들</strong></p> + +<ul> + <li>당신은 전체 문서를 doctype을 비롯해 {{htmlelement("html")}}, {{htmlelement("head")}}, {{htmlelement("body")}} elements 를 이용하여 다듬어야 합니다.</li> + <li>일반적으로 이 서한은 아래의 점을 제외하고 단락과 표제의 구조로 표시되어야합니다. 가장 높은 단계의 heading(the "Re:" lin) 하나와 두 번째 단계의 heading 세 개를 사용합니다</li> + <li>학기 시작 날짜, 스터디 주제들 그리고 이국적인 댄스들은 적절한 리스트 유형을 사용해서 마크 업을 하세요</li> + <li>두 개의 주소는 {{htmlelement("address")}} 요소 안에 위치해야 합니다. 주소의 각 줄은 새로운 문단이 아닌 새로운 줄에 위치해야합니다</li> +</ul> + +<p>Inline semantics:</p> + +<ul> + <li>The names of the sender and receiver (and "Tel" and "Email") should be marked up with strong importance.</li> + <li>The four dates in the document should be given appropriate elements containing machine-readable dates.</li> + <li>The first address and first date in the letter should be given a class attribute value of "sender-column"; the CSS you'll add later will then cause these to be right aligned, as should be the case in a classic letter layout.</li> + <li>The five acronyms/abbreviations in the main text of the letter should be marked up to provide expansions of each acronym/abbreviation.</li> + <li>The six sub/superscripts should be marked up appropriately — in the chemical formulae, and the numbers 103 and 104 (they should be 10 to the power or 3 and 4, respectively).</li> + <li>Try to mark up at least two appropriate words in the text with strong importance/emphasis.</li> + <li>There are two places where a hyperlink should be added; add appropriate links with titles. For the location that the links point to, just use http://example.com.</li> + <li>The university motto quote and citation should be marked up with appropriate elements.</li> +</ul> + +<p>The head of the document:</p> + +<ul> + <li>The character set of the document should be specified as utf-8 using an appropriate meta tag.</li> + <li>The author of the letter should be specified in an appropriate meta tag.</li> + <li>The provided CSS should be included inside an appropriate tag.</li> +</ul> + +<h2 id="Hints_and_tips">Hints and tips</h2> + +<ul> + <li>Use the <a href="https://validator.w3.org/">W3C HTML validator</a> to validate your HTML; you'll get bonus points if it validates.</li> + <li>You don't need to know any CSS to do this assessment; you just need to put the provided CSS inside an HTML element.</li> +</ul> + +<h2 id="Example">Example</h2> + +<p>The following screenshot shows an example of what the letter might look like after being marked up.</p> + +<p><img alt="Example" src="https://mdn.mozillademos.org/files/15811/Letter%20screengrab%202.png" style="border: 1px solid black; display: block; height: 1858px; margin: 0px auto; width: 931px;"></p> + +<h2 id="프로젝트">프로젝트</h2> + +<p>If you are following this assessment as part of an organized course, you should be able to give your work to your teacher/mentor for marking. If you are self-learning, then you can get the marking guide fairly easily by asking on the <a href="https://discourse.mozilla.org/t/marking-up-a-letter-assignment/24676">discussion thread about this exercise</a>, or in the <a href="irc://irc.mozilla.org/mdn">#mdn</a> IRC channel on <a href="https://wiki.mozilla.org/IRC">Mozilla IRC</a>. Try the exercise first — there is nothing to be gained by cheating!</p> + +<p>{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/Debugging_HTML", "Learn/HTML/Introduction_to_HTML/Structuring_a_page_of_content", "Learn/HTML/Introduction_to_HTML")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Getting_started">Getting started with HTML</a></li> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML">What’s in the head? Metadata in HTML</a></li> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals">HTML text fundamentals</a></li> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Creating_hyperlinks">Creating hyperlinks</a></li> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Advanced_text_formatting">Advanced text formatting</a></li> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Document_and_website_structure">Document and website structure</a></li> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Debugging_HTML">Debugging HTML</a></li> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Marking_up_a_letter">Marking up a letter</a></li> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Structuring_a_page_of_content">Structuring a page of content</a></li> +</ul> diff --git a/files/ko/learn/html/introduction_to_html/the_head_metadata_in_html/index.html b/files/ko/learn/html/introduction_to_html/the_head_metadata_in_html/index.html new file mode 100644 index 0000000000..da87edf6ee --- /dev/null +++ b/files/ko/learn/html/introduction_to_html/the_head_metadata_in_html/index.html @@ -0,0 +1,277 @@ +--- +title: head 태그에는 무엇이 있을까? HTML의 메타데이터 +slug: Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML +translation_of: Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/Getting_started", "Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals", "Learn/HTML/Introduction_to_HTML")}}</div> + +<p class="summary">HTML의 {{glossary("Head", "head")}}는 페이지를 열 때 웹 브라우저에 표시되지 않습니다. head는 {{htmlelement("title")}} 같은 페이지나, {{glossary("CSS")}}의 링크(HTML 컨텐츠를 CSS로 스타일링하기를 원한다면), 파비콘(favicon), 그리고 다른 메타데이터(작성자, 중요한 키워드와 같은 HTML에 대한 내용)를 포함합니다. 이 글에서는 위 내용들과 그 이상에 대해 다룰 것입니다. 이것은 head에 있어야하는 마크업이나 다른 코드들을 다루는데 좋은 기초가 될 것입니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">사전 지식:</th> + <td>HTML의 기본 구조, <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Getting_started">Getting started with HTML</a>문서의 내용을 사전에 읽으면 좋습니다.</td> + </tr> + <tr> + <th scope="row">목적:</th> + <td>HTML의 head을 사용하는 목적과 HTML 문서에 어떤 영향을 끼칠 수 있는지에 대해 학습합니다.</td> + </tr> + </tbody> +</table> + +<h2 id="HTML_head란">HTML head란?</h2> + +<p> <a href="/en-US/Learn/HTML/Introduction_to_HTML/Getting_started#Anatomy_of_an_HTML_document">HTML document we covered in the previous article</a>을 다시 봅시다.</p> + +<pre class="brush: html"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>My test page</title> + </head> + <body> + <p>This is my page</p> + </body> +</html></pre> + +<p>HTML {{htmlelement("head")}} 요소의 내용입니다. — 페이지를 열 때 브라우저에 표시되는 {{htmlelement("body")}}요소와 다르게, head의 내용는 페이지에 표시되지 않습니다. 대신에 head의 내용이 하는 일은 페이지에 대한 {{glossary("Metadata", "metadata")}}를 포함하는 것입니다. 위 예시의 head는 매우 간결합니다:</p> + +<pre class="brush: html"><head> + <meta charset="utf-8"> + <title>My test page</title> +</head></pre> + +<p>더 큰 웹 페이지의 경우엔 head가 꽤 많은 항목을 가질 수 있습니다. 가장 좋아하는 홈페이지로 가서 <a href="/en-US/docs/Learn/Discover_browser_developer_tools">developer tools</a>을 이용해 head를 살펴보십시오. 이 글의 목적은 head에 들어갈 수 있는 것들 전부를 어떻게 사용하는지 보여주기 위한 것이 아니라, 주로 head에 넣고 싶어할만한 것들을 익숙하게 하고 사용하는 방법을 가르쳐주는 것입니다.</p> + +<h2 id="제목_달기">제목 달기</h2> + +<p>우리는 action에서 {{htmlelement("title")}} 요소를 이미 봤습니다. 이것은 문서의 title을 추가하기 위해 사용될 수 있습니다. head는 body에서 최상위 부분에 들어가는{{htmlelement("h1")}} 요소와 헷갈릴 수 있습니다. <h1> 요소는 가끔 title을 가리키기도 하지만 이것은 엄연히 다릅니다!</p> + +<ul> + <li>{{htmlelement("h1")}} 요소는 일반적으로 페이지당 한 번 씩 사용되는데, 페이지 내용물의 제목이나 뉴스의 헤드라인을 표시하기 위해서 페이지를 열 때 브라우저에 표시됩니다.</li> + <li>{{htmlelement("title")}}은 (문서의 컨텐츠가 아니라) HTML문서 전체의 타이틀 표현하기 위한 메타데이터입니다. </li> +</ul> + +<h3 id="능동적_학습_간단한_예제_살펴보기">능동적 학습: 간단한 예제 살펴보기</h3> + +<ol> + <li>능동적인 학습을 시작하기 위해서, GitHub repo에가서 <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/the-html-head/title-example.html">title-example.html 페이지</a>의 복사본을 다운로드 하십시오. 다음 중 하나를 하면 됩니다: + + <ol> + <li>복사 붙여넣기를 새로운 텍스트 편집기에서 실행하고 당신이 알 만한 경로에 저장하십시오.</li> + <li>페이지에서 "Raw"버튼을 누르면, 새창에 Raw code가 나타납니다. 그런 다음 브라우저 메뉴에서 <em>File > Save Page As... </em>로 원하는 곳에 저장하십시오</li> + </ol> + </li> + <li>이제 당신의 브라우저에서 받은 파일을 여십시오.아래와 같이 보일 것입니다: + <p><img alt="A simple web page with the title set to <title> element, and the <h1> set to <h1> element." src="https://mdn.mozillademos.org/files/12323/title-example.png" style="display: block; margin: 0 auto;"><h1>컨텐츠가 보이는 곳이 어디인지 이제 명백할 것입니다. 그리고 <code><title></code> 컨텐츠도 어디에 있는지 알 수 있습니다!</p> + </li> + <li>텍스트 편집기에서도 이것을 열 수 있습니다. 이 요소들을 변경해보고, 페이지 새로고침하면서 즐겨보십시오.</li> +</ol> + +<p><code><title></code> 요소는 다른 방식으로 사용될 수도 있는데, 예를 들면 브라우저에서 사이트를 북마크할 때, <code><title></code>의 내용물을 추천하는 북마크 이름으로 사용하기도 합니다.</p> + +<p><img alt="A webpage being bookmarked in firefox; the bookmark name has been automatically filled in with the contents of the <title> element " src="https://mdn.mozillademos.org/files/12337/bookmark-example.png" style="display: block; margin: 0 auto;"></p> + +<p><code><title></code>은 아래에서 보는것 처럼 검색결과로 사용되기도 합니다.</p> + +<h2 id="메타데이터_<meta>_요소">메타데이터: <meta> 요소</h2> + +<p>메타데이터는 데이터를 설명하는 데이터이다 그리고 HTML에서 문서에 공식적으로 메타데이터를 적용하는 방법이 있습니다. — the {{htmlelement("meta")}} 요소. 물론 이 기사에서 다루고 있는 다른 것들도 메타 데이터라고 보면 됩니다. 페이지의 <head> 안에 다양한 형태의 <code><meta></code> 가 있습니다. 하지만 이 단계에서 모두 다루지는 않을 것입니다. 대신에 흔히 볼 수 있고 자주 쓰이는 것들에 대해 다뤄 보도록 하겠습니다.</p> + +<h3 id="문서의_character_인코딩을_특정하기">문서의 character 인코딩을 특정하기</h3> + +<p>위에서의 예제에서 , 아래의 줄이 포함됩니다:</p> + +<pre class="brush: html"><meta charset="utf-8"></pre> + +<p>이 요소는 문서의 character—문서에서 허용하는 문자 집합(character set)— encoding에 대해서 간단히 표시합니다 . <code>utf-8</code> 은 전세계적인 character 집합으로 많은 언어들을 문자들을 포함합니다. 이는 웹 페이지에서 어떤 문자라도 취급할 수 있다는 것을 의미합니다. 따라서 당신이 작성할 모든 페이지에서 character 집합을 utf-8로 지정하는것은 좋은 생각입니다! 예를 들어서 당신의 웹페이지는 영어나 일본어 모두 허용합니다:</p> + +<p><img alt="a web page containing English and Japanese characters, with the character encoding set to universal, or utf-8. Both languages display fine," src="https://mdn.mozillademos.org/files/12343/correct-encoding.png" style="display: block; margin: 0 auto;">예시로, 만약 (라틴 알파벳 사용을 위해서) <code>ISO-8859-1</code>로 characterset을 설정한다면, 페이지가 엉망으로 렌더링 될 것입니다:</p> + +<p><img alt="a web page containing English and Japanese characters, with the character encoding set to latin. The Japanese characters don't display correctly" src="https://mdn.mozillademos.org/files/12341/bad-encoding.png" style="display: block; height: 365px; margin: 0px auto; width: 604px;"></p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: 크롬과 같은 어떤 브라우저는 자동으로 잘못된 인코딩을 고치기 때문에, 어떤 브라우저를 사용하는가에 따라 이 문제를 겪지 않을 수도 있습니다. 그래도 다른 브라우저에서 있을 잠재적인 문제를 피하기 위하여 인코딩을 <code>utf-8</code> 으로 설정해야 합니다.</p> +</div> + +<h3 id="능동적_학습_character_인코딩_실험">능동적 학습: character 인코딩 실험</h3> + +<p>이것을 사용해 보기 위해 이전 섹션에서 익혔던 <code><title></code> (<a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/the-html-head/title-example.html">title-example.html page</a>)에서 얻은 간단한 HTMl 템플릿을 다시 켜고 멘타 문자 세트값을 <code>ISO-8859-1</code>로 변경한 다음, 페이지에 일본어를 추가합니다.</p> + +<pre class="brush: html"><p>Japanese example: ご飯が熱い。</p></pre> + +<h3 id="저자와_설명을_추가">저자와 설명을 추가</h3> + +<p>많은 <code><meta></code> 요소가 <code>name</code> 과 <code>content</code> 속성을 가집니다:</p> + +<ul> + <li><code>name</code> 은 메타 요소가 어떤 정보의 형태를 갖고 있는지 알려줍니다.</li> + <li><code>content</code>는 실제 메타데이터의 컨텐츠입니다.</li> +</ul> + +<p>이러한 두가지 메타데이터는 당신의 페이지에서 관리자를 정리하고 머릿말을 요약하는데 유용합니다. 아래의 예시를 보면:</p> + +<pre class="brush: html"><meta name="author" content="Chris Mills"> +<meta name="description" content="The MDN Learning Area aims to provide +complete beginners to the Web with all they need to know to get +started with developing web sites and applications."></pre> + +<p>저자를 지정하는 것은 콘텐츠 작성자에 대한 정보를 볼 수 있게 해준다. 일부 컨텐츠 관리 시스템에는 페이지 작성자 정보를 자동으로 추출해서 사용할 수 있는 기능이 있다.</p> + +<p>페이지 콘텐츠 관련 키워드를 포함시키는 것은 검색엔진에서 이 페이지가 더 많이 표시 될 가능성이 생기게 할 수 있다. (이러한 활동을 <a href="/en-US/docs/Glossary/SEO">Search Engine Optimization</a>, 또는 {{glossary("SEO")}} 라고 함.)</p> + +<h3 id="Active_learning_The_descriptions_use_in_search_engines">Active learning: The description's use in search engines</h3> + +<p>이 설명은 검색엔진 결과 페이지에서도 사용된다. 한번 알아보자.</p> + +<ol> + <li>다음 링크로 간다. <a href="https://developer.mozilla.org/en-US/">front page of The Mozilla Developer Network</a>.</li> + <li>페이지의 소스를 본다. (Right/<kbd>Ctrl</kbd> + click on the page, choose <em>View Page Source</em> from the context menu.)</li> + <li>메타 태그를 찾아본다. 아마 아래와 같은 형태로 생겼을 것이다. + <pre class="brush: html"><meta name="description" content="The Mozilla Developer Network (MDN) provides +information about Open Web technologies including HTML, CSS, and APIs for both +Web sites and HTML5 Apps. It also documents Mozilla products, like Firefox OS."></pre> + </li> + <li>지금 당신이 애용하는 검색엔진으로 "Mozilla Developer Network"를 찾아보라(우리는 YAHOO를 사용한다). 검색 결과를 보면, <code><meta></code> 및 <code><title></code> 요소의 컨텐츠 설명이 어떤 역할을 했는지 알 수 있을 것이다. + <p><img alt='A Yahoo search result for "Mozilla Developer Network"' src="https://mdn.mozillademos.org/files/12347/search-result.png" style="display: block; margin: 0 auto;"></p> + </li> +</ol> + +<div class="note"> +<p><strong>Note</strong>: Google에서는 메인 MDN 홈페이지 링크 아래에 MDN의 몇 가지 관련 서브 페이지가 표시된다. 이를 사이트 링크라고하며 Google의 웹 마스터 도구에서 구성 할 수 있다. 그리고 이는 Google 검색 엔진에서 사이트의 검색 결과를 개선하는 방법이다.</p> +</div> + +<div class="note"> +<p><strong>Note</strong>: 많은 <code><meta></code> 기능들이 더이상 사용되지 않는다. (예를들어 <code><meta name="keywords" content="fill, in, your, keywords, here"></code> 같은, 다른 검색 용어에 대해 해당 페이지의 관련성을 부여하기 위해 검색 엔진에 제공하던 키워드 등..) 스팸 발송자들이 키워드 목록에 수백 개의 키워드를 채워버리는 악용 사례가 생겨 버렸기 때문에 이것들은 검색 엔진들이 아예 무시를 해버리게 되었다.</p> +</div> + +<h3 id="Other_types_of_metadata">Other types of metadata</h3> + +<p>웹페이지를 돌아다니다 보면 다른 종류의 메타데이터들을 꽤 많이 볼 수 있다. 웹 사이트에서 볼 수있는 기능들은 특정 사이트 (예 : 소셜 네트워킹 사이트)에 사용할 수있는 특정 정보를 제공하도록 설계된 독점 제작물이다.</p> + +<p><a href="http://ogp.me/">Open Graph Data</a> 는 Facebook이 웹 사이트에 더 풍부한 메타 데이터를 제공하기 위해 발명한 메타 데이터 프로토콜이다. MDN 소스코드에서 다음과 같은 부분을 볼 수 있을 것이다.</p> + +<pre class="brush: html"><meta property="og:image" content="https://developer.cdn.mozilla.net/static/img/opengraph-logo.dc4e08e2f6af.png"> +<meta property="og:description" content="The Mozilla Developer Network (MDN) provides +information about Open Web technologies including HTML, CSS, and APIs for both Web sites +and HTML5 Apps. It also documents Mozilla products, like Firefox OS."> +<meta property="og:title" content="Mozilla Developer Network"></pre> + +<p>Facebook에서 MDN에 링크를 하면, 이미지와 설명이 함께 나타난다. 사용자에게는 더 좋은 정보를 보여줄 수 있는 것이다.</p> + +<p><img alt="Open graph protocol data from the MDN homepage as displayed on facebook, showing an image, title, and description." src="https://mdn.mozillademos.org/files/12349/facebook-output.png" style="display: block; margin: 0 auto;">Twitter 에서도 유사한 형태의 독점적인 자체 메타데이터를 가지고 있는데, 특정 웹사이트의 url이 twitter.com에 표시 될 때와 유사한 효과가 있다.</p> + +<pre class="brush: html"><meta name="twitter:title" content="Mozilla Developer Network"></pre> + +<h2 id="맞춤_아이콘_추가하기">맞춤 아이콘 추가하기</h2> + +<p>당신의 사이트 디자인을 좀 더 풍성하게 만들기 위해서 , 당신은 커스텀 아이콘 레퍼런스를 매타데이터에 추가하고 특정 콘텐츠에서 이것을 보여지게 할 수 있다.</p> + +<p>The humble favicon, which has been around for many years, was the first icon of this type, a 16 x 16 pixel icon used in multiple places. 각 열린 페이지의 탭이나 북마크 패널 페이지 쪽에서 favicon을 볼 수 있다.</p> + +<p>favicon은 다음과 같이 너의 사이트에 추가할 수 있다:</p> + +<ol> + <li>당신의 사이트의 인덱스 페이지와 같은 디렉토리에 <code>.ico</code> 포멧의 파일을 저장하라 (most browsers will support favicons in more common formats like <code>.gif</code> or <code>.png</code>, but using the ICO format will ensure it works as far back as Internet Explorer 6.)</li> + <li><code>다음 줄을 HTML <head>에 추가하여 favicon을 참조하라</code>: + <pre class="brush: html"><link rel="shortcut icon" href="favicon.ico" type="image/x-icon"></pre> + </li> +</ol> + +<p>북마크 페널의 페비콘이 그 예시이다:</p> + +<p><img alt="The Firefox bookmarks panel, showing a bookmarked example with a favicon displayed next to it." src="https://mdn.mozillademos.org/files/12351/bookmark-favicon.png" style="display: block; margin: 0 auto;"></p> + +<p>요즘은 많은 다른 아이콘 타입이 있다. 예를 들어서 MDN 홈페이지에서 다음과 같은 것을 발견할 것이다:</p> + +<pre class="brush: html"><!-- third-generation iPad with high-resolution Retina display: --> +<link rel="apple-touch-icon-precomposed" sizes="144x144" href="https://developer.cdn.mozilla.net/static/img/favicon144.a6e4162070f4.png"> +<!-- iPhone with high-resolution Retina display: --> +<link rel="apple-touch-icon-precomposed" sizes="114x114" href="https://developer.cdn.mozilla.net/static/img/favicon114.0e9fabd44f85.png"> +<!-- first- and second-generation iPad: --> +<link rel="apple-touch-icon-precomposed" sizes="72x72" href="https://developer.cdn.mozilla.net/static/img/favicon72.8ff9d87c82a0.png"> +<!-- non-Retina iPhone, iPod Touch, and Android 2.1+ devices: --> +<link rel="apple-touch-icon-precomposed" href="https://developer.cdn.mozilla.net/static/img/favicon57.a2490b9a2d76.png"> +<!-- basic favicon --> +<link rel="shortcut icon" href="https://developer.cdn.mozilla.net/static/img/favicon32.e02854fdcf73.png"></pre> + +<p>주석은 각 아이콘의 용도를 설명한다. 웹사이트가 iPad의 홈 화면에 저장 될 때 사용할 고해상도 아이콘을 제공하는 것 등을 포함한다.</p> + +<p>지금 당장 모든 아이콘을 구현할 줄 알아야 한다는 성급한 부담을 가질 필요는 없다. 이것은 고급 기능에 속하기도 하며, 이번 과정을 통해 여러 '지식'을 습득해야 가능하다. 이 페이지의 주된 목적은 다른 웹사이트의 소스 코드를 보며 그 '지식'을 습득할 수 있도록 하려는데에 있다.</p> + +<h2 id="HTML에_CSS_와_JavaScript_적용하기">HTML에 CSS 와 JavaScript 적용하기</h2> + +<p>현대의 모든 웹사이트는 상호작용 기능이 많은 영상 플레이어, 지도, 게임 등을 위해 {{glossary("JavaScript")}}가 필요하고, 이것들을 더 멋져 보이게 하기 위해 {{glossary("CSS")}}가 사용된다. 이것들은 {{htmlelement ( "link")}} 요소와 {{htmlelement ( "script")}} 요소를 사용하여 웹 페이지에 가장 일반적으로 적용된다.</p> + +<ul> + <li> + <p>{{htmlelement("link")}}는 항상 문서의 head 부분에 위치한다. 이것은 두 가지 속성을 취하는데, rel="stylesheet", 즉 문서의 스타일 시트임을 나타냄과 동시에 스타일 시트 파일의 경로를 포함하는 href를 내포한다.</p> + + <pre class="brush: html"><link rel="stylesheet" href="my-css-file.css"></pre> + </li> + <li> + <p>{{htmlelement("script")}} 는 head에 들어갈 필요가 없다. <code></body></code> 태그 바로 앞, 문서 본문의 맨 끝에 넣는 것이 좋으며, JavaScript를 적용하기 전에 모든 HTML 내용을 브라우저에서 읽었는지 확인하는 것이 좋다. 액세스 과정에서 JavaScript가 아직 존재하지 않는 요소라고 판단하며 에러가 날 수 있다.</p> + + <pre class="brush: html"><script src="my-js-file.js"></script></pre> + + <p><strong>Note</strong>: <code><script></code> 태그가 비어있다고 보일 수 도 있지만 그렇지 않으며, 반드시 태그를 닫아주어야 한다(</script>). 외부 스크립트 파일을 지정하는 대신 스크립트를 <code><script></code> 안에 넣을 수 도 있다.</p> + </li> +</ul> + +<h3 id="Active_learning_applying_CSS_and_JavaScript_to_a_page">Active learning: applying CSS and JavaScript to a page</h3> + +<ol> + <li>이 실습을 시작하려면, 같은 로컬 디렉토리 안에 <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/the-html-head/meta-example.html">meta-example.html</a>, <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/the-html-head/script.js">script.js</a> 그리고 <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/the-html-head/style.css">style.css</a> 파일을 미리 만들어 놓아야 한다. 올바른 이름과 파일 확장자로 저장되어 있는지 확인하는 것도 필수!</li> + <li>애용하는 브라우져에서 HTML 파일을 열고, 텍스트 에디터도 실행한다.</li> + <li>위에서 나온 설명대로 CSS와 JavaScript가 HTMl에 적용되도록 HTML에 {{htmlelement("link")}} 및 {{htmlelement("script")}} 를 추가한다.</li> +</ol> + +<p>HTML을 저장하고 브라우저를 새로 고치면 올바르게 변경된 것이다:</p> + +<p><img alt="Example showing a page with CSS and JavaScript applied to it. The CSS has made the page go green, whereas the JavaScript has added a dynamic list to the page." src="https://mdn.mozillademos.org/files/12359/js-and-css.png" style="display: block; margin: 0 auto;"></p> + +<ul> + <li>JavaScript가 빈 목록을 페이지에 추가했다. 이제 목록의 아무 곳이나 클릭하면 새 목록 항목에 대한 텍스트를 입력하라는 대화 상자가 나타난다. OK 버튼을 누르면 새로운 목록 아이템이 추가된다. 기존에 있던 목록의 아이템을 클릭하면 해당 아이템의 텍스트를 변경 할 수 있는 대화 상자가 나타난다.</li> + <li>CSS에 의해 배경이 녹색으로 변하고 텍스트가 커진다. 그리고 javaScript가 페이지에 추가 한 일부 스타일도 적용된다(검은색 테두리가 있는 빨간색 공간).</li> +</ul> + +<div class="note"> +<p><strong>Note</strong>: CSS나 JS를 적용하는데서 부터 애를 먹고 있으면 <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/the-html-head/css-and-js.html">css-and-js.html</a> 페이지를 참고하기를 추천한다.</p> +</div> + +<h2 id="문서의_기본_언어_설정">문서의 기본 언어 설정</h2> + +<p>마지막으로, 페이지의 언어를 설정 할 수도 있다. 이 작업은 <a href="/en-US/docs/Web/HTML/Global_attributes/lang">lang attribute</a> 을 여는 HTML 태그에 추가하여 수행 할 수 있다. (<a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/the-html-head/meta-example.html">meta-example.html</a> 과 아래 참조)</p> + +<pre class="brush: html"><html lang="en-US"></pre> + +<p>이것은 여러 방면에서 유용하다. HTML 문서는 언어가 설정되어 있으면 검색 엔진에 의해 보다 효과적으로 색인화되며(예를 들어 언어 별 결과에 올바르게 표시되도록..) 화면 판독기를 사용하여 시각장애가 있는 사용자에게 유용하다.(예: 6이라는 숫자는 프랑스어와 영어에서 모두 존재하지만, 각기 다른 발음이 적용된다.)</p> + +<p>또한, 문서의 하위 섹션을 다른 언어로 인식하도록 설정할 수도 있다. 예를들어 다음과 같이 일본어 일본어로 된 섹션에 대해서는 일본어로 인식하도록 할 수 있다:</p> + +<pre class="brush: html"><p>Japanese example: <span lang="jp">ご飯が熱い。</span>.</p></pre> + +<p>이 코드는 <a href="https://en.wikipedia.org/wiki/ISO_639-1">ISO 639-1</a> 표준에 따른다. <a href="https://www.w3.org/International/articles/language-tags/">Language tags in HTML and XML</a> 에서 자세한 내용을 확인할 수 있다.</p> + +<h2 id="요약">요약</h2> + +<p>HTML head에 대한 퀵 파이어 투어가 마무리 되었다. 여기에서 보고 할 수 있는 것보다 훨씬 많은 부분이 있지만, 지금 단계에서는 복잡하거나 어렵게 느껴질 수도 있을 것이고 단지 당신에게 지극히 일반적이고 기초적인 사용법만을 제시했을 뿐이다. </p> + +<p>{{PreviousMenuNext("Learn/HTML/Introduction_to_HTML/Getting_started", "Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals", "Learn/HTML/Introduction_to_HTML")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Getting_started">Getting started with HTML</a></li> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML">What’s in the head? Metadata in HTML</a></li> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/HTML_text_fundamentals">HTML text fundamentals</a></li> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Creating_hyperlinks">Creating hyperlinks</a></li> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Advanced_text_formatting">Advanced text formatting</a></li> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Document_and_website_structure">Document and website structure</a></li> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Debugging_HTML">Debugging HTML</a></li> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Marking_up_a_letter">Marking up a letter</a></li> + <li><a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Structuring_a_page_of_content">Structuring a page of content</a></li> +</ul> diff --git a/files/ko/learn/html/multimedia_and_embedding/ideo_and_audio_content/index.html b/files/ko/learn/html/multimedia_and_embedding/ideo_and_audio_content/index.html new file mode 100644 index 0000000000..d6930ac381 --- /dev/null +++ b/files/ko/learn/html/multimedia_and_embedding/ideo_and_audio_content/index.html @@ -0,0 +1,327 @@ +--- +title: 비디오 그리고 오디오 컨텐츠 +slug: Learn/HTML/Multimedia_and_embedding/ideo_and_audio_content +translation_of: Learn/HTML/Multimedia_and_embedding/Video_and_audio_content +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/HTML/Multimedia_and_embedding/Images_in_HTML", "Learn/HTML/Multimedia_and_embedding/Other_embedding_technologies", "Learn/HTML/Multimedia_and_embedding")}}</div> + +<p class="summary">이제 우리는 웹페이지에 간단한 이미지를 추가하는 것에 익숙해졌으므로, 다음 단계는 HTML 문서에 비디오와 오디오 플레이어를 추가하는 것이다! 이 기사에서는 <span class="seoSummary">{{htmlelement("video")}}</span>와 <span class="seoSummary">{{htmlelement("audio")}}</span> 요소들로 그렇게 하는 것에 대해 살펴보고, 동영상에 캡션/자막을 추가하는 방법을 살펴봄으로써 마무리하겠다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">사전 지식:</th> + <td>기본 컴퓨터 사용능력, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Installing_basic_software">기본 소프트웨어 설치</a>, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Dealing_with_files">파일 작업에 대한 기본 지식</a>, HTML 기본 원리(<a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Introduction_to_HTML/Getting_started">HTML 시작에서 다룬 내용</a>) 및 <a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Images_in_HTML">HTML의 이미지</a></td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>비디오 및 오디오 컨텐츠를 웹 페이지에 포함시키고 비디오에 캡션/자막을 추가하는 방법을 배웁니다.</td> + </tr> + </tbody> +</table> + +<h2 id="웹_상에서_비디오_그리고_오디오">웹 상에서 비디오 그리고 오디오</h2> + +<p>Web developers have wanted to use video and audio on the Web for a long time, ever since the early 2000s when we started to have bandwidth fast enough to support any kind of video (video files are much larger than text or even images.) In the early days, native web technologies such as HTML didn't have the ability to embed video and audio on the Web, so proprietary (or plugin-based) technologies like <a href="https://en.wikipedia.org/wiki/Adobe_Flash">Flash</a> (and later, <a href="https://en.wikipedia.org/wiki/Microsoft_Silverlight">Silverlight</a>) became popular for handling such content. This kind of technology worked ok, but it had a number of problems, including not working well with HTML/CSS features, security issues, and accessibility issues.</p> + +<p>A native solution would solve much of this if implemented correctly. Fortunately, a few years later the {{glossary("HTML5")}} specification had such features added, with the {{htmlelement("video")}} and {{htmlelement("audio")}} elements, and some shiny new {{Glossary("JavaScript")}} {{Glossary("API","APIs")}} for controlling them. We'll not be looking at JavaScript here — just the basic foundations that can be achieved with HTML.</p> + +<p>We won't be teaching you how to produce audio and video files — that requires a completely different skillset. We have provided you with <a href="https://github.com/mdn/learning-area/tree/master/html/multimedia-and-embedding/video-and-audio-content">sample audio and video files and example code</a> for your own experimentation, in case you are unable to get hold of your own.</p> + +<div class="note"> +<p><strong>Note</strong>: Before you begin here, you should also know that there are quite a few OVPs (online video providers) like <a href="https://www.youtube.com/">YouTube</a>, <a href="https://www.dailymotion.com">Dailymotion</a>, and <a href="https://vimeo.com/">Vimeo</a>, and online audio providers like <a href="https://soundcloud.com/">Soundcloud</a>. Such companies offer a convenient, easy way to host and consume videos, so you don't have to worry about the enormous bandwidth consumption. OVPs even usually offer ready-made code for embedding video/audio in your webpages; if you use that route, you can avoid some of the difficulties we discuss in this article. We'll be discussing this kind of service a bit more in the next article.</p> +</div> + +<h3 id="The_<video>_element">The <video> element</h3> + +<p>The {{htmlelement("video")}} element allows you to embed a video very easily. A really simple example looks like this:</p> + +<pre class="brush: html notranslate"><video src="rabbit320.webm" controls> + <p>Your browser doesn't support HTML5 video. Here is a <a href="rabbit320.webm">link to the video</a> instead.</p> +</video></pre> + +<p>The features of note are:</p> + +<dl> + <dt>{{htmlattrxref("src","video")}}</dt> + <dd>In the same way as for the {{htmlelement("img")}} element, the <code>src</code> (source) attribute contains a path to the video you want to embed. It works in exactly the same way.</dd> + <dt>{{htmlattrxref("controls","video")}}</dt> + <dd>Users must be able to control video and audio playback (it's especially critical for people who have <a href="https://en.wikipedia.org/wiki/Epilepsy#Epidemiology">epilepsy</a>.) You must either use the <code>controls</code> attribute to include the browser's own control interface, or build your interface using the appropriate <a href="/en-US/docs/Web/API/HTMLMediaElement">JavaScript API</a>. At a minimum, the interface must include a way to start and stop the media, and to adjust the volume.</dd> + <dt>The paragraph inside the <code><video></code> tags</dt> + <dd>This is called <strong>fallback content</strong> — this will be displayed if the browser accessing the page doesn't support the <code><video></code> element, allowing us to provide a fallback for older browsers. This can be anything you like; in this case, we've provided a direct link to the video file, so the user can at least access it some way regardless of what browser they are using.</dd> +</dl> + +<p>The embedded video will look something like this:</p> + +<p><img alt="A simple video player showing a video of a small white rabbit" src="https://mdn.mozillademos.org/files/12794/simple-video.png" style="display: block; height: 592px; margin: 0px auto; width: 589px;"></p> + +<p>You can <a href="http://mdn.github.io/learning-area/html/multimedia-and-embedding/video-and-audio-content/simple-video.html">try the example live</a> here (see also the <a href="https://github.com/mdn/learning-area/blob/master/html/multimedia-and-embedding/video-and-audio-content/simple-video.html">source code</a>.)</p> + +<h3 id="Using_multiple_source_formats_to_improve_compatibility">Using multiple source formats to improve compatibility</h3> + +<p>There's a problem with the above example, which you may have noticed already if you've tried to access the live link above with an older browser like Internet Explorer or even an older version of Safari. The video won't play, because different browsers support different video (and audio) formats. Fortunately, there are things you can do to help prevent this from being a problem.</p> + +<h4 id="Contents_of_a_media_file">Contents of a media file</h4> + +<p>First, let's go through the terminology quickly. Formats like MP3, MP4 and WebM are called <strong><a href="/en-US/docs/Web/Media/Formats/Containers">container formats</a></strong>. They define a structure in which the audio and/or video tracks that make up the media are stored, along with metadata describing the media, what codecs are used to encode its channels, and so forth.</p> + +<p>A WebM file containing a movie which has a main video track and one alternate angle track, plus audio for both English and Spanish, in addition to audio for an English commentary track can be conceptualized as shown in the diagram below. Also included are text tracks containing closed captions for the feature film, Spanish subtitles for the film, and English captions for the commentary.</p> + +<p><a href="https://mdn.mozillademos.org/files/16898/ContainersAndTracks.svg"><img alt="Diagram conceptualizing the contents of a media file at the track level." src="https://mdn.mozillademos.org/files/16898/ContainersAndTracks.svg" style="height: 472px; width: 640px;"></a></p> + +<p>The audio and video tracks within the container hold data in the appropriate format for the codec used to encode that media. Different formats are used for audio tracks versus video tracks. Each audio track is encoded using an <a href="/en-US/docs/Web/Media/Formats/Audio_codecs">audio codec</a>, while video tracks are encoded using (as you probably have guessed) <a href="/en-US/docs/Web/Media/Formats/Video_codecs">a video codec</a>. As we talked about before, different browsers support different video and audio formats, and different container formats (like MP3, MP4, and WebM, which in turn can contain different types of video and audio).</p> + +<p>For example:</p> + +<ul> + <li>A WebM container typically packages Vorbis or Opus audio with VP8/VP9 video. This is supported in all modern browsers, though older versions may not work.</li> + <li>An MP4 container often packages AAC or MP3 audio with H.264 video. This is also supported in all modern browsers, as well as Internet Explorer.</li> + <li>The Ogg container tends to use Vorbis audio and Theora video. This is best supported in Firefox and Chrome, but has basically been superseded by the better quality WebM format.</li> +</ul> + +<p>There are some special cases. For example, for some types of audio, a codec's data is often stored without a container, or with a simplified container. One such instance is the FLAC codec, which is stored most commonly in FLAC files, which are just raw FLAC tracks.</p> + +<p>Another such situation is the always-popular MP3 file. An "MP3 file" is actually an MPEG-1 Audio Layer III (MP3) audio track stored within an MPEG or MPEG-2 container. This is especially interesting since while most browsers don't support using MPEG media in the {{HTMLElement("video")}} and {{HTMLElement("audio")}} elements, they may still support MP3 due to its popularity.</p> + +<p>An audio player will tend to play an audio track directly, e.g. an MP3 or Ogg file. These don't need containers.</p> + +<h4 id="Media_file_support_in_browsers">Media file support in browsers</h4> + +<div class="callout-box"> +<p>Why do we have this problem? It turns out that several popular formats, such as MP3 and MP4/H.264, are excellent but are encumbered by patents; that is, there are patents covering some or all of the technology that they're based upon. In the United States, patents covered MP3 until 2017, and H.264 is encumbered by patents through at least 2027.</p> + +<p>Because of those patents, browsers that wish to implement support for those codecs must pay typically enormous license fees. In addition, some people simply prefer to avoid restricted software and prefer to use only open formats. Due to these legal and preferential reasons, web developers find themselves having to support multiple formats to capture their entire audience.</p> +</div> + +<p>The codecs described in the previous section exist to compress video and audio into manageable files, since raw audio and video are both exceedingly large. Each web browser supports an assortment of <strong>{{Glossary("Codec","codecs")}}</strong>, like Vorbis or H.264, which are used to convert the compressed audio and video into binary data and back. Each codec offers its own advantages and drawbacks, and each container may also offer its own positive and negative features affecting your decisions about which to use.</p> + +<p>Things become slightly more complicated because not only does each browser support a different set of container file formats, they also each support a different selection of codecs. In order to maximize the likelihood that your web site or app will work on a user's browser, you may need to provide each media file you use in multiple formats. If your site and the user's browser don't share a media format in common, your media simply won't play.</p> + +<p>Due to the intricacies of ensuring your app's media is viewable across every combination of browsers, platforms, and devices you wish to reach, choosing the best combination of codecs and container can be a complicated task. See {{SectionOnPage("/en-US/docs/Web/Media/Formats/Containers", "Choosing the right container")}} for help selecting the container file format best suited for your needs; similarly, see {{SectionOnPage("/en-US/docs/Web/Media/Formats/Video_codecs", "Choosing a video codec")}} and {{SectionOnPage("/en-US/docs/Web/Media/Formats/Audio_codecs", "Choosing an audio codec")}} for help selecting the first media codecs to use for your content and your target audience.</p> + +<p>One additional thing to keep in mind: mobile browsers may support additional formats not supported by their desktop equivalents, just like they may not support all the same formats the desktop version does. On top of that, both desktop and mobile browsers <em>may</em> be designed to offload handling of media playback (either for all media or only for specific types it can't handle internally). This means media support is partly dependent on what software the user has installed.</p> + +<p>So how do we do this? Take a look at the following <a href="https://github.com/mdn/learning-area/blob/gh-pages/html/multimedia-and-embedding/video-and-audio-content/multiple-video-formats.html">updated example</a> (<a href="http://mdn.github.io/learning-area/html/multimedia-and-embedding/video-and-audio-content/multiple-video-formats.html">try it live here</a>, also):</p> + +<pre class="brush: html notranslate"><video controls> + <source src="rabbit320.mp4" type="video/mp4"> + <source src="rabbit320.webm" type="video/webm"> + <p>Your browser doesn't support HTML5 video. Here is a <a href="rabbit320.mp4">link to the video</a> instead.</p> +</video></pre> + +<p>Here we've taken the <code>src</code> attribute out of the actual {{HTMLElement("video")}} tag, and instead included separate {{htmlelement("source")}} elements that point to their own sources. In this case the browser will go through the {{HTMLElement("source")}} elements and play the first one that it has the codec to support. Including WebM and MP4 sources should be enough to play your video on most platforms and browsers these days.</p> + +<p>Each <code><source></code> element also has a {{htmlattrxref("type", "source")}} attribute. This is optional, but it is advised that you include it. The <code>type</code> attribute contains the {{glossary("MIME type")}} of the file specified by the <code><source></code>, and browsers can use the <code>type</code> to immediately skip videos they don't understand. If<code>type</code> isn't included, browsers will load and try to play each file until they find one that works, which obviously takes time and is an unnecessary use of resources.</p> + +<p>Refer to our <a href="/en-US/docs/Web/Media/Formats">guide to media types and formats</a> for help selecting the best containers and codecs for your needs, as well as to look up the right MIME types to specify for each.</p> + +<h3 id="Other_<video>_features">Other <video> features</h3> + +<p>There are a number of other features you can include when displaying an HTML video. Take a look at our next example:</p> + +<pre class="brush: html notranslate"><video controls width="400" height="400" + autoplay loop muted + poster="poster.png"> + <source src="rabbit320.mp4" type="video/mp4"> + <source src="rabbit320.webm" type="video/webm"> + <p>Your browser doesn't support HTML video. Here is a <a href="rabbit320.mp4">link to the video</a> instead.</p> +</video> +</pre> + +<p>The resulting UI looks something like this:</p> + +<p><img alt="A video player showing a poster image before it plays. The poster image says HTML5 video example, OMG hell yeah!" src="https://mdn.mozillademos.org/files/16949/poster_screenshot_updated.png" style="border-style: solid; border-width: 1px; display: block; height: 470px; margin: 0px auto; width: 413px;"></p> + +<p>The new features are:</p> + +<dl> + <dt>{{htmlattrxref("width","video")}} and {{htmlattrxref("height","video")}}</dt> + <dd>You can control the video size either with these attributes or with {{Glossary("CSS")}}. In both cases, videos maintain their native width-height ratio — known as the <strong>aspect ratio</strong>. If the aspect ratio is not maintained by the sizes you set, the video will grow to fill the space horizontally, and the unfilled space will just be given a solid background color by default.</dd> + <dt>{{htmlattrxref("autoplay","video")}}</dt> + <dd>Makes the audio or video start playing right away, while the rest of the page is loading. You are advised not to use autoplaying video (or audio) on your sites, because users can find it really annoying.</dd> + <dt>{{htmlattrxref("loop","video")}}</dt> + <dd>Makes the video (or audio) start playing again whenever it finishes. This can also be annoying, so only use if really necessary.</dd> + <dt>{{htmlattrxref("muted","video")}}</dt> + <dd>Causes the media to play with the sound turned off by default.</dd> + <dt>{{htmlattrxref("poster","video")}}</dt> + <dd>The URL of an image which will be displayed before the video is played. It is intended to be used for a splash screen or advertising screen.</dd> + <dt>{{htmlattrxref("preload","video")}}</dt> + <dd> + <p>Used for buffering large files; it can take one of three values:</p> + + <ul> + <li><code>"none"</code> does not buffer the file</li> + <li><code>"auto"</code> buffers the media file</li> + <li><code>"metadata"</code> buffers only the metadata for the file</li> + </ul> + </dd> +</dl> + +<p>You can find the above example available to <a href="http://mdn.github.io/learning-area/html/multimedia-and-embedding/video-and-audio-content/extra-video-features.html">play live on Github</a> (also <a href="https://github.com/mdn/learning-area/blob/gh-pages/html/multimedia-and-embedding/video-and-audio-content/extra-video-features.html">see the source code</a>.) Note that we haven't included the <code>autoplay</code> attribute in the live version — if the video starts to play as soon as the page loads, you don't get to see the poster!</p> + +<h3 id="The_<audio>_element">The <audio> element</h3> + +<p>The {{htmlelement("audio")}} element works just like the {{htmlelement("video")}} element, with a few small differences as outlined below. A typical example might look like so:</p> + +<pre class="brush: html notranslate"><audio controls> + <source src="viper.mp3" type="audio/mp3"> + <source src="viper.ogg" type="audio/ogg"> + <p>Your browser doesn't support HTML5 audio. Here is a <a href="viper.mp3">link to the audio</a> instead.</p> +</audio></pre> + +<p>This produces something like the following in a browser:</p> + +<p><img alt="A simple audio player with a play button, timer, volume control, and progress bar" src="https://mdn.mozillademos.org/files/12798/audio-player.png" style="display: block; height: 413px; margin: 0px auto; width: 626px;"></p> + +<div class="note"> +<p><strong>Note</strong>: You can <a href="http://mdn.github.io/learning-area/html/multimedia-and-embedding/video-and-audio-content/multiple-audio-formats.html">run the audio demo live</a> on Github (also see the <a href="https://github.com/mdn/learning-area/blob/gh-pages/html/multimedia-and-embedding/video-and-audio-content/multiple-audio-formats.html">audio player source code</a>.)</p> +</div> + +<p>This takes up less space than a video player, as there is no visual component — you just need to display controls to play the audio. Other differences from HTML video are as follows:</p> + +<ul> + <li>The {{htmlelement("audio")}} element doesn't support the <code>width</code>/<code>height</code> attributes — again, there is no visual component, so there is nothing to assign a width or height to.</li> + <li>It also doesn't support the <code>poster</code> attribute — again, no visual component.</li> +</ul> + +<p>Other than this, <code><audio></code> supports all the same features as <code><video></code> — review the above sections for more information about them.</p> + +<h3 id="Restarting_media_playback">Restarting media playback</h3> + +<p>At any time, you can reset the media to the beginning—including the process of selecting the best media source, if more than one is specified using {{HTMLElement("source")}} elements—by calling the element's {{domxref("HTMLMediaElement.load", "load()")}} method:</p> + +<pre class="brush: js notranslate">const mediaElem = document.getElementById("my-media-element"); +mediaElem.load();</pre> + +<h3 id="Detecting_track_addition_and_removal">Detecting track addition and removal</h3> + +<p>You can monitor the track lists within a media element to detect when tracks are added to or removed from the element's media. For example, you can watch for the {{event("addtrack")}} event being fired on the associated {{domxref("AudioTrackList")}} object (retrieved via {{domxref("HTMLMediaElement.audioTracks")}}) to be informed when audio tracks are added to the media:</p> + +<pre class="brush: js notranslate">const mediaElem = document.querySelector("video"); +mediaElem.audioTracks.onaddtrack = function(event) { + audioTrackAdded(event.track); +} +</pre> + +<p>You'll find more information about this in our {{domxref("TrackEvent")}} documentation.</p> + +<h2 id="Displaying_video_text_tracks">Displaying video text tracks</h2> + +<p>Now we'll discuss a slightly more advanced concept that is really useful to know about. Many people can't or don't want to hear the audio/video content they find on the Web, at least at certain times. For example:</p> + +<ul> + <li>Many people have auditory impairments (such as being hard of hearing or deaf) so can't hear the audio clearly if at all.</li> + <li>Others may not be able to hear the audio because they are in noisy environments (like a crowded bar when a sports game is being shown).</li> + <li>Similarly, in environments where having the audio playing would be a distraction or disruption (such as in a library or when a partner is trying to sleep), having captions can be very useful.</li> + <li>People who don't speak the language of the video might want a text transcript or even translation to help them understand the media content.</li> +</ul> + +<p>Wouldn't it be nice to be able to provide these people with a transcript of the words being spoken in the audio/video? Well, thanks to HTML video, you can. To do so we use the <a href="/en-US/docs/Web/API/Web_Video_Text_Tracks_Format">WebVTT</a> file format and the {{htmlelement("track")}} element.</p> + +<div class="note"> +<p><strong>Note</strong>: "Transcribe" means "to write down spoken words as text." The resulting text is a "transcript."</p> +</div> + +<p>WebVTT is a format for writing text files containing multiple strings of text along with metadata such as the time in the video at which each text string should be displayed, and even limited styling/positioning information. These text strings are called <strong>cues</strong>, and there are several kinds of cues which are used for different purposes. The most common cues are:</p> + +<dl> + <dt>subtitles</dt> + <dd>Translations of foreign material, for people who don't understand the words spoken in the audio.</dd> + <dt>captions</dt> + <dd>Synchronized transcriptions of dialog or descriptions of significant sounds, to let people who can't hear the audio understand what is going on.</dd> + <dt>timed descriptions</dt> + <dd>Text which should be spoken by the media player in order to describe important visuals to blind or otherwise visually impaired users.</dd> +</dl> + +<p>A typical WebVTT file will look something like this:</p> + +<pre class="eval line-numbers language-html notranslate"><code class="language-html">WEBVTT + +1 +00:00:22.230 --> 00:00:24.606 +This is the first subtitle. + +2 +00:00:30.739 --> 00:00:34.074 +This is the second. + + ...</code> +</pre> + +<p>To get this displayed along with the HTML media playback, you need to:</p> + +<ol> + <li>Save it as a <code>.vtt</code> file in a sensible place.</li> + <li>Link to the <code>.vtt</code> file with the {{htmlelement("track")}} element. <code><track></code> should be placed within <code><audio></code> or <code><video></code>, but after all <code><source></code> elements. Use the {{htmlattrxref("kind","track")}} attribute to specify whether the cues are <code>subtitles</code>, <code>captions</code>, or <code>descriptions</code>. Further, use {{htmlattrxref("srclang","track")}} to tell the browser what language you have written the subtitles in.</li> +</ol> + +<p>Here's an example:</p> + +<pre class="brush: html notranslate"><video controls> + <source src="example.mp4" type="video/mp4"> + <source src="example.webm" type="video/webm"> + <track kind="subtitles" src="subtitles_en.vtt" srclang="en"> +</video></pre> + +<p>This will result in a video that has subtitles displayed, kind of like this:</p> + +<p><img alt='Video player with stand controls such as play, stop, volume, and captions on and off. The video playing shows a scene of a man holding a spear-like weapon, and a caption reads "Esta hoja tiene pasado oscuro."' src="https://mdn.mozillademos.org/files/7887/video-player-with-captions.png" style="display: block; height: 365px; margin: 0px auto; width: 593px;"></p> + +<p>For more details, please read <a href="/en-US/Apps/Build/Audio_and_video_delivery/Adding_captions_and_subtitles_to_HTML5_video">Adding captions and subtitles to HTML5 video</a>. You can <a href="http://iandevlin.github.io/mdn/video-player-with-captions/">find the example</a> that goes along with this article on Github, written by Ian Devlin (see the <a href="https://github.com/iandevlin/iandevlin.github.io/tree/master/mdn/video-player-with-captions">source code</a> too.) This example uses some JavaScript to allow users to choose between different subtitles. Note that to turn the subtitles on, you need to press the "CC" button and select an option — English, Deutsch, or Español.</p> + +<div class="note"> +<p><strong>Note</strong>: Text tracks also help you with {{glossary("SEO")}}, since search engines especially thrive on text. Text tracks even allow search engines to link directly to a spot partway through the video.</p> +</div> + +<h3 id="Active_learning_Embedding_your_own_audio_and_video">Active learning: Embedding your own audio and video</h3> + +<p>For this active learning, we'd (ideally) like you to go out into the world and record some of your own video and audio — most phones these days allow you to record audio and video very easily, and provided you can transfer it on to your computer, you can use it. You may have to do some conversion to end up with a WebM and MP4 in the case of video, and an MP3 and Ogg in the case of audio, but there are enough programs out there to allow you to do this without too much trouble, such as <a href="http://www.mirovideoconverter.com/">Miro Video Converter</a> and <a href="https://sourceforge.net/projects/audacity/">Audacity</a>. We'd like you to have a go!</p> + +<p>If you are unable to source any video or audio, then you can feel free to use our <a href="https://github.com/mdn/learning-area/tree/master/html/multimedia-and-embedding/video-and-audio-content">sample audio and video files</a> to carry out this exercise. You can also use our sample code for reference.</p> + +<p>We would like you to:</p> + +<ol> + <li>Save your audio and video files in a new directory on your computer.</li> + <li>Create a new HTML file in the same directory, called <code>index.html</code>.</li> + <li>Add {{HTMLElement("audio")}} and {{HTMLElement("video")}} elements to the page; make them display the default browser controls.</li> + <li>Give both of them {{HTMLElement("source")}} elements so that browsers will find the audio format they support best and load it. These should include {{htmlattrxref("type", "source")}} attributes.</li> + <li>Give the <code><video></code> element a poster that will be displayed before the video starts to be played. Have fun creating your own poster graphic.</li> +</ol> + +<p>For an added bonus, you could try researching text tracks, and work out how to add some captions to your video.</p> + +<h2 id="Test_your_skills!">Test your skills!</h2> + +<p>You've reached the end of this article, but can you remember the most important information? You can find some further tests to verify that you've retained this information before you move on — see <a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Video_and_audio_content/Test_your_skills:_Multimedia_and_embedding">Test your skills: Multimedia and embedding</a>. Note that the third assessment question in this test assumes knowledge of some of the techniques covered in the <a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Other_embedding_technologies">next article</a>, so you may want to read that before attempting it.</p> + +<h2 id="Summary">Summary</h2> + +<p>And that's a wrap; we hope you had fun playing with video and audio in web pages! In the next article, we'll look at other ways of embedding content on the Web, using technologies like {{htmlelement("iframe")}} and {{htmlelement("object")}}.</p> + +<h2 id="See_also">See also</h2> + +<ul> + <li>The HTML media elements: {{htmlelement("audio")}}, {{htmlelement("video")}}, {{htmlelement("source")}}, and {{htmlelement("track")}}</li> + <li><a href="/en-US/Apps/Build/Audio_and_video_delivery/Adding_captions_and_subtitles_to_HTML5_video">Adding captions and subtitles to HTML5 video</a></li> + <li><a href="/en-US/docs/Web/Apps/Fundamentals/Audio_and_video_delivery">Audio and Video delivery</a>: A LOT of detail about putting audio and video onto web pages using HTML and JavaScript.</li> + <li><a href="/en-US/docs/Web/Apps/Fundamentals/Audio_and_video_manipulation">Audio and Video manipulation</a>: A LOT of detail about manipulating audio and video using JavaScript (for example adding filters.)</li> + <li>Automated options to <a href="http://www.inwhatlanguage.com/blog/translate-video-audio/">translate multimedia</a>.</li> + <li><a href="/en-US/docs/Web/Media">Web media technologies</a></li> + <li><a href="/en-US/docs/Web/Media/Formats">Guide to media types and formats on the web</a></li> +</ul> + +<p>{{PreviousMenuNext("Learn/HTML/Multimedia_and_embedding/Images_in_HTML", "Learn/HTML/Multimedia_and_embedding/Other_embedding_technologies", "Learn/HTML/Multimedia_and_embedding")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Images_in_HTML">Images in HTML</a></li> + <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Video_and_audio_content">Video and audio content</a></li> + <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Other_embedding_technologies">From <object> to <iframe> — other embedding technologies</a></li> + <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Adding_vector_graphics_to_the_Web">Adding vector graphics to the Web</a></li> + <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images">Responsive images</a></li> + <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Mozilla_splash_page">Mozilla splash page</a></li> +</ul> diff --git a/files/ko/learn/html/multimedia_and_embedding/images_in_html/index.html b/files/ko/learn/html/multimedia_and_embedding/images_in_html/index.html new file mode 100644 index 0000000000..c0ebcc07e9 --- /dev/null +++ b/files/ko/learn/html/multimedia_and_embedding/images_in_html/index.html @@ -0,0 +1,496 @@ +--- +title: HTML의 이미지 +slug: Learn/HTML/Multimedia_and_embedding/Images_in_HTML +translation_of: Learn/HTML/Multimedia_and_embedding/Images_in_HTML +--- +<div>{{LearnSidebar}}</div> + +<div>{{NextMenu("Learn/HTML/Multimedia_and_embedding/Video_and_audio_content", "Learn/HTML/Multimedia_and_embedding")}}</div> + +<p class="summary">초창기의 웹에는 텍스트만 있었고 조금 지루했습니다. 다행히도 웹 페이지 안에 이미지 (및 보다 흥미로운 유형의 컨텐츠)를 삽입하는 기능이 추가되기까지는 오래 걸리지 않았습니다. 시작해볼 수 있는 다른 유형의 멀티미디어가 있지만 단순한 이미지를 웹 페이지에 삽입하는 데 사용되는 {{htmlelement ( "img")}} 요소로 쉽게 시작해 보겠습니다. 이 글에서는 기초내용 부터 심층적으로 사용하는 방법, {{htmlelement("figure")}}를 사용하여 캡션을 주석으로 추가하는 방법, {{htmlelement("CSS")}}배경 이미지와 관련된 사용 방법을 자세히 설명합니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">선행사항:</th> + <td>기본 컴퓨터 활용 능력, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Installing_basic_software">기본 소프트웨어 설치</a>, <a href="https://developer.mozilla.org/en-US/Learn/Getting_started_with_the_web/Dealing_with_files">파일작업</a>에 대한 기본 지식, HTML 기초 지식 익숙 (<a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Getting_started">HTML 시작하기</a>에서 설명)</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>간단한 이미지를 HTML에 삽입하고, 캡션을 사용하여 주석을 추가하는 방법과 HTML 이미지가 CSS 배경 이미지와 관련되는 방법을 배우십시오.</td> + </tr> + </tbody> +</table> + +<h2 id="웹페이지에_어떻게_이미지를_넣을까"><strong>웹페이지에 어떻게 이미지를 넣을까?</strong></h2> + +<p>이미지를 웹사이트에 넣기위해서 {{htmlelement("img")}} 요소를 사용합니다. 이것은 텍스트 내용이나 클로징 태그를 갖지 않는 {{glossary("비어있는 요소 (empty element)")}}이며, 적어도 <code>src</code>(풀네임인 source라고 불리곤 합니다)라는 속성 하나는 사용되어야합니다. <code>src</code> 속성은 당신이 페이지에 삽입하고자 하는 이미지를 가리키는 경로를 포함합니다. 그 경로는 {{htmlelement("a")}} 요소의 <code>href</code> 속성 값처럼 상대경로여도, 절대경로여도 됩니다.</p> + +<div class="note"> +<p><strong>노트</strong>: 계속하기 전에 절대경로, 상대경로에 대해 복습하기 위해 <a href="https://developer.mozilla.org/en-US/Learn/HTML/Introduction_to_HTML/Creating_hyperlinks#A_quick_primer_on_URLs_and_paths">A quick primer on URLs and paths</a>를 읽어보세요.</p> +</div> + +<p>예를 들어, 당신의 이미지 파일 이름이 <code>dinosaur.jpg</code> 이고, 당신의 HTML 페이지와 같은 디렉토리 아래에 위치한다면 이런 식으로 이미지를 삽입할 수 있습니다:</p> + +<pre class="brush: html notranslate"><img src="dinosaur.jpg"> +</pre> + +<p>그 이미지가 HTML페이지와 같은 디렉토리 하의 <code>images</code> 라는 하위 디렉토리에 있다면 (이러한 방식은 구글이 {{glossary("SEO")}}/색인을 위해 추천합니다), 이런 식으로 삽입할 수 있습니다:</p> + +<pre class="brush: html notranslate"><img src="images/dinosaur.jpg"></pre> + +<div class="note"> +<p><strong>노트:</strong> 검색 엔진은 이미지 파일 이름을 읽고 SEO에 포함시킵니다. 따라서 그 내용을 기술하는 파일 이름을 사용하세요. <code>img835.png</code>.보다는 <code>dinosaur.jpg</code> 가 낫습니다.</p> +</div> + +<p>절대경로를 사용해서 이미지를 삽입할 수도 있습니다. 예를 들면: </p> + +<pre class="brush: html notranslate"><img src="https://www.example.com/images/dinosaur.jpg"> +</pre> + +<p>그러나 이건 무의미합니다. DNS 서버로부터 IP 주소를 처음부터 다시 찾아보는 등 브라우저가 더 많은 일을 하게 만들기 때문입니다. 당신은 거의 항상 당신의 HTML과 같은 서버에 이미지를 두게 될 것입니다.</p> + +<div class="warning"> +<p><strong>주의사항</strong>: 대부분의 이미지들은 저작권 적용 대상입니다. 따라서, </p> + +<p>1) 당신이 그 이미지에 대한 소유권을 갖고 있거나<br> + 2) 당신이 그 이미지의 소유자로부터 명확한 서류상의 허가를 받았거나<br> + 3) 그 이미지가 실제로 공공재라는 충분한 증거가 있는 경우</p> + +<p>가 아니면 당신의 웹페이지에 이미지를 <strong>게시하지 마십시오. </strong></p> + +<p>저작권 침해는 불법이며 비윤리적입니다. 또한 당신의 <code>src</code> 속성이 링크하도록 허가받지 않은 누군가의 웹사이트에 호스팅 된 이미지를 가리키지 않도록 하십시오. 이러한 행위를 "핫 링킹(hot linking)"이라고 합니다. 누군가의 대역폭을 훔쳐 쓰는 것은 불법입니다. 이것은 당신의 페이지를 느리게 만들고, 그 이미지가 삭제되거나 무언가 부끄러운 걸로 바뀌어도 당신은 그것을 통제할 권한이 없습니다.</p> +</div> + +<p>위에서 쓴 우리의 코드는 이러한 결과를 보여줄 것입니다:</p> + +<p><img alt='A basic image of a dinosaur, embedded in a browser, with "Images in HTML" written above it' src="https://mdn.mozillademos.org/files/12700/basic-image.png" style="display: block; height: 700px; margin: 0px auto; width: 700px;"></p> + +<div class="note"> +<p><strong>Note</strong>: {{htmlelement("img")}} 와 {{htmlelement("video")}} 와 같은 element들을 대체 element라고 하기도 합니다. 그 이유는 element의 내용과 크기가 element 그 자체가 아니라, 외부적인 요소(이미지나 비디오)에 의해 결정되기 때문입니다.</p> +</div> + +<div class="note"> +<p><strong>Note</strong>: 완성된 예제들을 <a href="https://mdn.github.io/learning-area/html/multimedia-and-embedding/images-in-html/index.html">running on Github</a>에서 확인하실 수 있습니다. (<a href="https://github.com/mdn/learning-area/blob/master/html/multimedia-and-embedding/images-in-html/index.html">source code</a> 도 참고하세요.)</p> +</div> + +<h3 id="Alternative_text">Alternative text</h3> + +<p>다음으로 살펴볼 속성은 <code>alt</code>이다. 이 값은 이미지가 보여지지 않을 경우를 대비해서 이미지를 설명할 수 있는 글을 값으로 가진다. 예를 들어, 위의 코드를 다음과 같이 바꿀 수 있다:</p> + +<pre class="brush: html notranslate"><img src="images/dinosaur.jpg" + alt="The head and torso of a dinosaur skeleton; + it has a large head with long sharp teeth"></pre> + +<p><code>alt</code> 를 잘 작성하였는지 확인하기 위한 가장 쉬운 방법은 파일 이름을 고의로 틀리게 적는 것이다. 예를 들어 이미지 파일의 이름을 <code>dinosooooor.jpg</code> 로 바꾼다면 브라우저는 이미지를 보여주는 대신, alt의 내용을 보여줄 것이다:</p> + +<p><img alt="The Images in HTML title, but this time the dinosaur image is not displayed, and alt text is in its place." src="https://mdn.mozillademos.org/files/12702/alt-text.png" style="display: block; height: 700px; margin: 0px auto; width: 700px;"></p> + +<p>alt는 왜 굳이 사용되거나 필요한걸까? alt는 여러가지 이유로 유용하게 사용된다:</p> + +<ul> + <li>사용자가 시각적인 장애를 가지고 있는 경우 <a href="https://en.wikipedia.org/wiki/Screen_reader">screen reader</a>가 그 내용을 읽어줄 수 있을 것이다. 사실 alt를 가지고 있다는 것만으로 대부분의 사용자들에게 도움이 될 수 있다.</li> + <li>위에서 살펴봤듯이, 파일명을 잘못 적거나 path를 잘못 적었을 수도 있다.</li> + <li>아직까지도 텍스트만 지원되는 브라우저(예를 들면 : <a href="https://en.wikipedia.org/wiki/Lynx_%28web_browser%29">Lynx</a>)를 사용하는 사용자들이 있기 때문에 이미지 지원이 안되는 사용자들도 있다.</li> + <li>텍스트를 제공하여 검색엔진이 이를 활용할 수 있도록 할 수 있다. 예를 들어, 검색엔진의 검색 query가 alt 텍스트와 일치할 수 있을 것이다.</li> + <li>사용자가 데이터 통신량과 방해요소를 줄이기 위해 고의적으로 이미지를 꺼 놓았을 수도 있다. 이러한 현상은 휴대기기 사용자들에게서 많이 나타나며 대역폭이 비싸거나 제한된 지역에서도 나타난다.</li> +</ul> + +<p>그렇다면 <code>alt</code> 안에 정확히 무엇을 써야될까? 그 내용은 이미지가 <em>왜</em> 사용되었는지에 따라 다르다. 다른말로 해서, 이미지가 나타나지 않으면:</p> + +<ul> + <li><strong>장식. </strong>You should use {{anch("CSS background images")}} for decorative images, but if you must use HTML, add a blank <code>alt=""</code>. If the image isn't part of the content, a screen reader shouldn't waste time reading it.</li> + <li><strong>내용. </strong>If your image provides significant information, provide the same information in a <em>brief </em><code>alt</code> text – or even better, in the main text which everybody can see. Don't write redundant <code>alt</code> text. How annoying would it be for a sighted user if all paragraphs were written twice in the main content? If the image is described adequately by the main text body, you can just use <code>alt=""</code>.</li> + <li><strong>링크.</strong> If you put an image inside {{htmlelement("a")}} tags, to turn an image into a link, you still must provide <a href="/en-US/Learn/HTML/Introduction_to_HTML/Creating_hyperlinks#Use_clear_link_wording">accessible link text</a>. In such cases you may, either, write it inside the same <code><a></code> element, or inside the image's <code>alt</code> attribute – whichever works best in your case.</li> + <li><strong>텍스트.</strong> 텍스트는 이미지로 나타내면 안된다. 메인 헤딩이 drop shadow가 필요하다면 이미지로 넣는 방법 대신에 <a href="/en-US/docs/Web/CSS/text-shadow">CSS</a>를 사용하도록 하자. 최후의 수단으로 이미지를 사용해야된다면 <code>alt</code> 속성에 설명을 적어두길 바란다.</li> +</ul> + +<p>기본적으로, 이미지가 나타나지 않을 때, 사용자에게 충분할 설명을 제공하는 것이 목적이다. 이러한 방법을 통해 사용자가 이미지를 보지 않고도 내용을 충분히 전달 받을 수 있다. 이미지를 브라우저에서 끄고 어떻게 나타나는지 관찰해보자. 이미지가 나타나지 않을 때 alt의 소중함을 깨닫게 될 것이다.</p> + +<div class="note"> +<p><strong>Note</strong>: 더 자세한 정보를 얻길 원하다면 <a href="/en-US/docs/Learn/Accessibility/HTML#Text_alternatives">Text Alternatives</a>를 클릭.</p> +</div> + +<h3 id="Width_and_height">Width and height</h3> + +<p><code>width</code> 와 <code>height</code> 속성을 통해 이미지의 크기를 조정할 수 있다. 이미지의 크기를 알아내는 몇가지 방법이 있는데 Mac은 <kbd>Cmd</kbd> + <kbd>I</kbd> 를 통해 이미지 정보를 볼 수 있다. 예제로 돌아와서, 우리는 이렇게 해볼 수 있다:</p> + +<pre class="brush: html notranslate"><img src="images/dinosaur.jpg" + alt="The head and torso of a dinosaur skeleton; + it has a large head with long sharp teeth" + width="400" + height="341"></pre> + +<p>평범한 경우에 위와 같은 방법은 디스플레이에 큰 차이를 주지 않는다. 그러나 만약에 이미지가 로딩중이어서 아직 페이지에 안나타나더라도 브라우저는 지정된 크기의 공간을 이미지를 위해 할당해둔다:</p> + +<p><img alt="The Images in HTML title, with dinosaur alt text, displayed inside a large box that results from width and height settings" src="https://mdn.mozillademos.org/files/12706/alt-text-with-width-height.png" style="display: block; height: 700px; margin: 0px auto; width: 700px;"></p> + +<p>이미지 크기를 지정해두는 것은 좋은 습관이며 이를 통해, 페이지가 더 빠르고 순조롭게 로딩될 수 있다.</p> + +<p>그러나 HTML 속성을 통해 이미지의 크기를 조정하는 것은 바람직하지 않다. 이미지 크기를 원본보다 크게 잡으면 원하지 않는 방향으로 나타날 수 있으며 사용자의 필요에 맞지 않는 불필요한 대역폭을 사용할 수도 있다. 또한, <a href="https://en.wikipedia.org/wiki/Aspect_ratio_%28image%29">aspect ratio</a>를 지키지 않으면 이미지가 왜곡되어 나타날 수도 있다. 이미지 편집기를 통해서 크기를 변경한 후에 웹페이지에 올리는 것이 바람직하다.</p> + +<div class="note"> +<p><strong>Note</strong>: 이미지 크기를 변경해야 한다면 <a href="/en-US/docs/Learn/CSS">CSS</a> 를 사용하도록 하자.</p> +</div> + +<h3 id="Image_titles">Image titles</h3> + +<p>As <a href="https://developer.mozilla.org/en-US/Learn/HTML/Introduction_to_HTML/Creating_hyperlinks#Adding_supporting_information_with_%3Ctitle%3E">with links</a>, you can also add <code>title</code> attributes to images, to provide further supporting information if needed. In our example, we could do this:</p> + +<pre class="brush: html notranslate"><img src="images/dinosaur.jpg" + alt="The head and torso of a dinosaur skeleton; + it has a large head with long sharp teeth" + width="400" + height="341" + title="A T-Rex on display in the Manchester University Museum"></pre> + +<p>This gives us a tooltip, just like link titles:</p> + +<p><img alt="The dinosaur image, with a tooltip title on top of it that reads A T-Rex on display at the Manchester University Museum " src="https://mdn.mozillademos.org/files/12708/image-with-title.png" style="display: block; height: 341px; margin: 0px auto; width: 400px;"></p> + +<p>Image titles aren't essential to include. It is often better to include such supporting information in the main article text, rather than attached to the image. However, they are useful in some circumstances; for example, in an image gallery when you have no space for captions.</p> + +<h3 id="Active_learning_embedding_an_image">Active learning: embedding an image</h3> + +<p>It is now your turn to play! This active learning section will have you up and running with a simple embedding exercise. You are provided with a basic {{htmlelement("img")}} tag; we'd like you to embed the image located at the following URL:</p> + +<p>https://raw.githubusercontent.com/mdn/learning-area/master/html/multimedia-and-embedding/images-in-html/dinosaur_small.jpg</p> + +<p>Earlier we said to never hotlink to images on other servers, but this is just for learning purposes, so we'll let you off this one time.</p> + +<p>We would also like you to:</p> + +<ul> + <li>Add some alt text, and check that it works by misspelling the image URL.</li> + <li>Set the image's correct <code>width</code> and <code>height</code> (hint; it is 200px wide and 171px high), then experiment with other values to see what the effect is.</li> + <li>Set a <code>title</code> on the image.</li> +</ul> + +<p>If you make a mistake, you can always reset it using the <em>Reset</em> button. If you get really stuck, press the <em>Show solution</em> button to see an answer:</p> + +<div class="hidden"> +<h6 id="Playable_code">Playable code</h6> + +<pre class="brush: html notranslate"><h2>Live output</h2> + +<div class="output" style="min-height: 50px;"> +</div> + +<h2>Editable code</h2> +<p class="a11y-label">Press Esc to move focus away from the code area (Tab inserts a tab character).</p> + +<textarea id="code" class="input" style="min-height: 100px; width: 95%"> +<img> +</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Reset"> + <input id="solution" type="button" value="Show solution"> +</div></pre> + +<pre class="brush: css notranslate">html { + font-family: sans-serif; +} + +h2 { + font-size: 16px; +} + +.a11y-label { + margin: 0; + text-align: right; + font-size: 0.7rem; + width: 98%; +} + +body { + margin: 10px; + background: #f5f9fa; +}</pre> + +<pre class="brush: js notranslate">var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var output = document.querySelector('.output'); +var code = textarea.value; +var userEntry = textarea.value; + +function updateCode() { + output.innerHTML = textarea.value; +} + +reset.addEventListener('click', function() { + textarea.value = code; + userEntry = textarea.value; + solutionEntry = htmlSolution; + solution.value = 'Show solution'; + updateCode(); +}); + +solution.addEventListener('click', function() { + if(solution.value === 'Show solution') { + textarea.value = solutionEntry; + solution.value = 'Hide solution'; + } else { + textarea.value = userEntry; + solution.value = 'Show solution'; + } + updateCode(); +}); + +var htmlSolution = '<img src="https://raw.githubusercontent.com/mdn/learning-area/master/html/multimedia-and-embedding/images-in-html/dinosaur_small.jpg"\n alt="The head and torso of a dinosaur skeleton; it has a large head with long sharp teeth"\n width="200"\n height="171"\n title="A T-Rex on display in the Manchester University Museum">'; +var solutionEntry = htmlSolution; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); + +// stop tab key tabbing out of textarea and +// make it write a tab at the caret position instead + +textarea.onkeydown = function(e){ + if (e.keyCode === 9) { + e.preventDefault(); + insertAtCaret('\t'); + } + + if (e.keyCode === 27) { + textarea.blur(); + } +}; + +function insertAtCaret(text) { + var scrollPos = textarea.scrollTop; + var caretPos = textarea.selectionStart; + + var front = (textarea.value).substring(0, caretPos); + var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length); + textarea.value = front + text + back; + caretPos = caretPos + text.length; + textarea.selectionStart = caretPos; + textarea.selectionEnd = caretPos; + textarea.focus(); + textarea.scrollTop = scrollPos; +} + +// Update the saved userCode every time the user updates the text area code + +textarea.onkeyup = function(){ + // We only want to save the state when the user code is being shown, + // not the solution, so that solution is not saved over the user code + if(solution.value === 'Show solution') { + userEntry = textarea.value; + } else { + solutionEntry = textarea.value; + } + + updateCode(); +};</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code', 700, 350, "", "", "hide-codepen-jsfiddle") }}</p> + +<h2 id="Annotating_images_with_figures_and_figure_captions">Annotating images with figures and figure captions</h2> + +<p>Speaking of captions, there are a number of ways that you could add a caption to go with your image. For example, there would be nothing to stop you doing this:</p> + +<pre class="brush: html notranslate"><div class="figure"> + <img src="images/dinosaur.jpg" + alt="The head and torso of a dinosaur skeleton; + it has a large head with long sharp teeth" + width="400" + height="341"> + + <p>A T-Rex on display in the Manchester University Museum.</p> +</div></pre> + +<p>This is ok. It contains the content you need, and is nicely stylable using CSS. But there is a problem here: there is nothing that semantically links the image to its caption, which can cause problems for screen readers. For example, when you have 50 images and captions, which caption goes with which image?</p> + +<p>A better solution, is to use the HTML5 {{htmlelement("figure")}} and {{htmlelement("figcaption")}} elements. These are created for exactly this purpose: to provide a semantic container for figures, and clearly link the figure to the caption. Our above example could be rewritten like this:</p> + +<pre class="notranslate"><figure> + <img src="images/dinosaur.jpg" + alt="The head and torso of a dinosaur skeleton; + it has a large head with long sharp teeth" + width="400" + height="341"> + + <figcaption>A T-Rex on display in the Manchester University Museum.</figcaption> +</figure></pre> + +<p>The {{htmlelement("figcaption")}} element tells browsers, and assistive technology that the caption describes the other content of the {{htmlelement("figure")}} element.</p> + +<div class="note"> +<p><strong>Note</strong>: From an accessibility viewpoint, captions and {{htmlattrxref('alt','img')}} text have distinct roles. Captions benefit even people who can see the image, whereas {{htmlattrxref('alt','img')}} text provides the same functionality as an absent image. Therefore, captions and <code>alt</code> text shouldn't just say the same thing, because they both appear when the image is gone. Try turning images off in your browser and see how it looks.</p> +</div> + +<p>A figure doesn't have to be an image. It is an independent unit of content that:</p> + +<ul> + <li>Expresses your meaning in a compact, easy-to-grasp way.</li> + <li>Could go in several places in the page's linear flow.</li> + <li>Provides essential information supporting the main text.</li> +</ul> + +<p>A figure could be several images, a code snippet, audio, video, equations, a table, or something else.</p> + +<h3 id="Active_learning_creating_a_figure">Active learning: creating a figure</h3> + +<p>In this active learning section, we'd like you to take the finished code from the previous active learning section, and turn it into a figure:</p> + +<ul> + <li>Wrap it in a {{htmlelement("figure")}} element.</li> + <li>Copy the text out of the <code>title</code> attribute, remove the <code>title</code> attribute, and put the text inside a {{htmlelement("figcaption")}} element below the image.</li> +</ul> + +<p>If you make a mistake, you can always reset it using the <em>Reset</em> button. If you get really stuck, press the <em>Show solution</em> button to see an answer:</p> + +<div class="hidden"> +<h6 id="Playable_code_2">Playable code 2</h6> + +<pre class="brush: html notranslate"><h2>Live output</h2> + +<div class="output" style="min-height: 50px;"> +</div> + +<h2>Editable code</h2> +<p class="a11y-label">Press Esc to move focus away from the code area (Tab inserts a tab character).</p> + +<textarea id="code" class="input" style="min-height: 100px; width: 95%"> +</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Reset"> + <input id="solution" type="button" value="Show solution"> +</div></pre> + +<pre class="brush: css notranslate">html { + font-family: sans-serif; +} + +h2 { + font-size: 16px; +} + +.a11y-label { + margin: 0; + text-align: right; + font-size: 0.7rem; + width: 98%; +} + +body { + margin: 10px; + background: #f5f9fa; +}</pre> + +<pre class="brush: js notranslate">var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var output = document.querySelector('.output'); +var code = textarea.value; +var userEntry = textarea.value; + +function updateCode() { + output.innerHTML = textarea.value; +} + +reset.addEventListener('click', function() { + textarea.value = code; + userEntry = textarea.value; + solutionEntry = htmlSolution; + solution.value = 'Show solution'; + updateCode(); +}); + +solution.addEventListener('click', function() { + if(solution.value === 'Show solution') { + textarea.value = solutionEntry; + solution.value = 'Hide solution'; + } else { + textarea.value = userEntry; + solution.value = 'Show solution'; + } + updateCode(); +}); + +var htmlSolution = '<figure>\n <img src="https://raw.githubusercontent.com/mdn/learning-area/master/html/multimedia-and-embedding/images-in-html/dinosaur_small.jpg"\n alt="The head and torso of a dinosaur skeleton; it has a large head with long sharp teeth"\n width="200"\n height="171">\n <figcaption>A T-Rex on display in the Manchester University Museum</figcaption>\n</figure>'; +var solutionEntry = htmlSolution; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); + +// stop tab key tabbing out of textarea and +// make it write a tab at the caret position instead + +textarea.onkeydown = function(e){ + if (e.keyCode === 9) { + e.preventDefault(); + insertAtCaret('\t'); + } + + if (e.keyCode === 27) { + textarea.blur(); + } +}; + +function insertAtCaret(text) { + var scrollPos = textarea.scrollTop; + var caretPos = textarea.selectionStart; + + var front = (textarea.value).substring(0, caretPos); + var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length); + textarea.value = front + text + back; + caretPos = caretPos + text.length; + textarea.selectionStart = caretPos; + textarea.selectionEnd = caretPos; + textarea.focus(); + textarea.scrollTop = scrollPos; +} + +// Update the saved userCode every time the user updates the text area code + +textarea.onkeyup = function(){ + // We only want to save the state when the user code is being shown, + // not the solution, so that solution is not saved over the user code + if(solution.value === 'Show solution') { + userEntry = textarea.value; + } else { + solutionEntry = textarea.value; + } + + updateCode(); +};</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code_2', 700, 350, "", "", "hide-codepen-jsfiddle") }}</p> + +<h2 id="CSS_background_images">CSS background images</h2> + +<p>You can also use CSS to embed images into webpages (and JavaScript, but that's another story entirely). The CSS {{cssxref("background-image")}} property, and the other <code>background-*</code> properties, are used to control background image placement. For example, to place a background image on every paragraph on a page, you could do this:</p> + +<pre class="brush: css notranslate">p { + background-image: url("images/dinosaur.jpg"); +}</pre> + +<p>The resulting embedded image, is arguably easier to position and control than HTML images. So why bother with HTML images? As hinted to above, CSS background images are for decoration only. If you just want to add something pretty to your page to enhance the visuals, this is fine. Though, such images have no semantic meaning at all. They can't have any text equivalents, are invisible to screen readers, etc. This is HTML images time to shine!</p> + +<p>Summing up: if an image has meaning, in terms of your content, you should use an HTML image. If an image is purely decoration, you should use CSS background images.</p> + +<div class="note"> +<p><strong>Note</strong>: You'll learn a lot more about <a href="/en-US/docs/Learn/CSS/Styling_boxes/Backgrounds">CSS background images</a> in our <a href="/en-US/docs/Learn/CSS">CSS</a> topic.</p> +</div> + +<p>That's all for now. We have covered images and captions in detail. In the next article we'll move it up a gear, looking at how to use HTML to embed video and audio in web pages.</p> + +<p>{{NextMenu("Learn/HTML/Multimedia_and_embedding/Video_and_audio_content", "Learn/HTML/Multimedia_and_embedding")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Images_in_HTML">Images in HTML</a></li> + <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Video_and_audio_content">Video and audio content</a></li> + <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Other_embedding_technologies">From <object> to <iframe> — other embedding technologies</a></li> + <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Adding_vector_graphics_to_the_Web">Adding vector graphics to the Web</a></li> + <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images">Responsive images</a></li> + <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Mozilla_splash_page">Mozilla splash page</a></li> +</ul> diff --git a/files/ko/learn/html/multimedia_and_embedding/index.html b/files/ko/learn/html/multimedia_and_embedding/index.html new file mode 100644 index 0000000000..33a3bf4aad --- /dev/null +++ b/files/ko/learn/html/multimedia_and_embedding/index.html @@ -0,0 +1,77 @@ +--- +title: Multimedia and embedding +slug: Learn/HTML/Multimedia_and_embedding +tags: + - Assessment + - Audio + - Beginner + - CodingScripting + - Flash + - Guide + - HTML + - Images + - Landing + - Learn + - NeedsTranslation + - SVG + - TopicStub + - Video + - iframes + - imagemaps + - responsive +translation_of: Learn/HTML/Multimedia_and_embedding +--- +<p>{{LearnSidebar}}</p> + +<p class="summary">우리는 이 과정에서 지금까지 많은 텍스트를 살펴 봤지만 텍스트만을 사용한 웹은 따분합니다. 보다 흥미로운 내용으로 웹을 생생하게 만드는 방법을 살펴 보도록 합시다! 여기에서는 HTML을 사용하여 이미지를 포함 할 수있는 다양한 방법과 비디오, 오디오 및 웹 페이지 전체를 포함하는 방법을 비롯하여 웹 페이지에 멀티미디어를 포함하는 방법을 살펴 보도록 하겠습니다.</p> + +<h2 id="전제조건">전제조건</h2> + +<p>이 단원을 시작하기 전에 앞서 <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">HTML소개</a>에서 설명한대로 HTML에 대한 기본 지식이 있어야합니다. 이 모듈 (또는 이와 비슷한 것)을 사용해 보지 않았다면, 처음부터 다시 시작후 돌아오세요!</p> + +<div class="note"> +<p><strong>Note</strong>: 자신만의 파일을 만들수 없는 컴퓨터/테블릿/그외 기기에서 작업하는 경우, 코드 예제를 (대부분을) <a href="https://jsbin.com/">JSBin</a> 이나 <a href="https://thimble.mozilla.org/">Thimble</a>같은 온라인 코딩 프로그램을 통해 수행해 볼 수 있습니다</p> +</div> + +<h2 id="가이드">가이드</h2> + +<p>이 단원에는 웹 페이지에 멀티미디어를 삽입하는 모든 기본 사항을 설명하는 다음 문서가 포함되어 있습니다.</p> + +<dl> + <dt><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Images_in_HTML">HTML 이미지</a></dt> + <dd>여기에는 고려해야할 다른 종류의 멀티미디어들이 있지만, 간단한 이미지를 웹페이지에 삽입하는데 사용되는 일반적인 {{htmlelement("img")}} 엘리먼트를 사용하는것이 합리적입니다. 이번 내용에서는 {{htmlelement("figure")}} 사용하여, 기본적인 내용 및 캡션을 주석으로 추가하는 방법, CSS 배경 이미지와의 관계에 대해 자세히 다룰 것입니다.</dd> + <dt><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Video_and_audio_content">비디오와 오디오 컨텐츠</a></dt> + <dd>다음으로, {{htmlelement("video")}} 와{{htmlelement("audio")}} 엘리먼트를 사용하여 페이지에 비디오 및 오디오를 포함하는 방법을 살펴 보겠습니다. 기본기능을 포함, 여러종류의 브라우저에 다양한 파일 포맷에 접근하는 법, 캡션 및 자막 추가, 구형 브라우저에 대한 폴백 (fallback) 추가 방법 등 다양한 기능을 제공합니다.</dd> + <dt><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Other_embedding_technologies"><object> 로부터 <iframe>까지 — 기타 임베딩 기술</a></dt> + <dd>여기서는 웹 페이지에 다양한 콘텐츠 유형을 삽입 할 수있게 해주는 몇가지 추가적인 요소를 살펴봅니다 : {{htmlelement("iframe")}}, {{htmlelement("embed")}} 그리고 {{htmlelement("object")}} 엘리먼트입니다. <code><iframe></code>은 다른 웹 페이지를 삽입하기위한 것이고, 나머지 두 개는 PDF, SVG 및 플래시까지 포함 할 수 있습니다. — 이 기술들은 사라지는 중이지만 여전히 볼수 있을것입니다.</dd> + <dt><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Adding_vector_graphics_to_the_Web">Vector graphics 웹에 추가하기</a></dt> + <dd>Vector graphics 는 특정한 상황에서 매우 유용할 수 있습니다. Vector graphics 는 <span style="font-size: 1rem; letter-spacing: -0.00278rem;">PNG/JPG와 같은 일반적인 형식과 달리 확대 시 왜곡/픽셀레이트가 발생하지 않으며, 스케일링 시 매끄러운 상태를 유지할 수 있습니다. 이 글에서는 Vector graphics 가 무엇인지, 웹 페이지에 인기 있는 </span> {{glossary("SVG")}} <span style="font-size: 1rem; letter-spacing: -0.00278rem;">포맷을 포함시키는 방법에 대해 소개합니다.</span></dd> + <dt><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images">Responsive images(반응형 이미지)</a></dt> + <dd> + <p>휴대전화에서 데스크톱 컴퓨터에 이르기까지, 웹을 검색할 수 있는 매우 다양한 유형의 장치들로 인해서 형성된 현대 웹 세계를 마스터하기 위한 필수적인 개념은 반응형 디자인입니다. 이는 다양한 화면 크기, 해상도 등에 맞춰 기능을 자동으로 변경할 수 있는 웹 페이지를 만드는 것을 말합니다. 이것은 나중에 CSS 모듈에서 훨씬 더 자세히 살펴보겠지만, 현재로서는 HTML이 {{htmlelement("picture")}} 요소를 포함하여 반응형 이미지를 만드는 데 사용할 수 있는 도구를 살펴보기로 하겠습니다.</p> + </dd> +</dl> + +<h2 id="평가">평가</h2> + +<p>아래의 평가는 위의 가이드에서 다루는 HTML 기본 사항에 대한 이해를 테스트합니다.</p> + +<dl> + <dt><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Mozilla_splash_page">Mozilla splash page</a></dt> + <dd> + <p>이 평가에서, 우리는 당신이 Mozilla 에 관한 모든 펑키한 스플래시 페이지에 몇 개의 이미지와 비디오를 추가하도록 하며, 이 모듈의 기사에서 논의된 몇 가지 기술에 대하여 당신의 지식을 테스트할 것입니다!</p> + </dd> +</dl> + +<h2 id="같이_보기">같이 보기</h2> + +<dl> + <dt><a href="/en-US/docs/Learn/HTML/Howto/Add_a_hit_map_on_top_of_an_image">이미지 위에 히트맵 추가</a></dt> + <dd> + <p>이미지 맵은 이미지 링크의 다른 부분을 다른 곳에 연결하는 메커니즘을 제공합니다(당신이 클릭하는 각 나라에 대한 추가 정보들과 연결되는 지도를 생각해 봅시다). 이 기술은 때때로 유용하게 활용될 수 있습니다.</p> + </dd> + <dt><a href="https://teach.mozilla.org/activities/web-lit-basics-two/">Web literacy basics 2</a></dt> + <dd> + <p>An excellent Mozilla foundation course that explores and tests some of the skills talked about in the <em>Multimedia and embedding</em> module. Dive deeper into the basics of composing webpages, designing for accessibility, sharing resources, using online media, and working open (meaning that your content is freely available, and shareable by others).</p> + </dd> +</dl> diff --git a/files/ko/learn/html/multimedia_and_embedding/responsive_images/index.html b/files/ko/learn/html/multimedia_and_embedding/responsive_images/index.html new file mode 100644 index 0000000000..14ecf00e1f --- /dev/null +++ b/files/ko/learn/html/multimedia_and_embedding/responsive_images/index.html @@ -0,0 +1,261 @@ +--- +title: 반응형 이미지 +slug: Learn/HTML/Multimedia_and_embedding/Responsive_images +translation_of: Learn/HTML/Multimedia_and_embedding/Responsive_images +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/HTML/Multimedia_and_embedding/Adding_vector_graphics_to_the_Web", "Learn/HTML/Multimedia_and_embedding/Mozilla_splash_page", "Learn/HTML/Multimedia_and_embedding")}}</div> + +<div> +<p class="summary">이 글에서 우리는 반응형 이미지(Responsive images)의 — 해상도, 스크린 크기 등이 다른 수많은 기기들에서 정상적으로 표시되는 이미지 — 개념과 구현을 위해 HTML에서 제공하는 도구에 대해 배울 것이다. 반응형 이미지는, 이후에 여러분이 배워야 할 CSS 과정 중 <a href="https://developer.mozilla.org/ko/docs/Learn/CSS">반응형 웹 디자인</a>의 일부이다.</p> +</div> + +<table class="learn-box nostripe standard-table"> + <tbody> + <tr> + <th scope="row">전제조건:</th> + <td><a href="https://developer.mozilla.org/ko/docs/Learn/HTML/Introduction_to_HTML">HTML 기본 태그</a>, <a href="https://developer.mozilla.org/ko/docs/Learn/HTML/Multimedia_and_embedding/Images_in_HTML">이미지를 웹페이지에 넣는 방법</a></td> + </tr> + <tr> + <th scope="row">학습목표:</th> + <td>웹사이트에서 반응형 이미지를 구현하기 위해 사용하는 {{htmlattrxref("srcset", "img")}}이나 {{htmlelement("picture")}} 요소 같은 기능의 사용법을 배운다.</td> + </tr> + </tbody> +</table> + +<h2 id="반응형_이미지를_사용하는_이유">반응형 이미지를 사용하는 이유?</h2> + +<p>일반적인 웹 사이트를 떠올려 보라. 헤더 이미지가 있을 것이고, 헤더 이후 본문에는 이미지가 몇 개 있을 것이다. 헤더 이미지는 헤더의 전체 가로 너비를 자치할 것이고, 본문 이미지는 본문 영역 안에서 어느 정도를 차지할 것이다. 아래 사이트의 이미지 처럼 말이다.</p> + +<p><img alt="Our example site as viewed on a wide screen - here the first image works ok, as it is big enough to see the detail in the center." src="https://mdn.mozillademos.org/files/12940/picture-element-wide.png" style="display: block; height: 554px; margin: 0px auto; width: 700px;"></p> + +<p>노트북이나 데스크톱처럼 화면이 넓은 기기에서는 잘 작동할 것이다(<a href="http://mdn.github.io/learning-area/html/multimedia-and-embedding/responsive-images/not-responsive.html">실제 예시는 여기에 있고</a>, Github에서 <a href="https://github.com/mdn/learning-area/blob/master/html/multimedia-and-embedding/responsive-images/not-responsive.html">소스코드</a>를 볼 수 있다.) CSS에 대해 너무 깊이 들어가고 싶진 않지만, 이정도는 이야기하자.</p> + +<ul> + <li>사이트 전체 너비는 최대 1200픽셀이다. 뷰포트가 1200픽셀이 넘는 경우 남는 공간 안에서 가운데 정렬된다. 1200픽셀 이하 뷰포트에서는 뷰포트 전체 너비의 100%가 된다.</li> + <li>헤더 이미지는, 너비가 얼마든간에 언제나 헤더의 가운데 오게 설정했다. 좁은 화면에서 본다면, 이미지의 가운데 있는 가장 중요한 부분(사람들)은 여전히 보인다. 그리고 나머지 좌우 부분은 보이지 않는다. 높이는 200픽셀이다.</li> + <li>본문 이미지는 웹사이트 너비가 이미지보다 작아지면, 줄어들기 시작해 삐져나가지 않고 언제나 사이트 너비 안에 있게 된다.</li> +</ul> + +<p>그러나, 좁은 화면 기기로 사이트를 보기 시작하면 문제가 생긴다. 헤더는 괜찮아 보이지만, 모바일 기기에서는 화면 높이를 너무 많이 차지하기 시작한다. 이 사이즈에서는, 본문 첫번째 사진의 사람들이 나타나기 어렵다.</p> + +<p><img alt="Our example site as viewed on a narrow screen; the first image has shrunk to the point where it is hard to make out the detail on it." src="https://mdn.mozillademos.org/files/12936/non-responsive-narrow.png" style="display: block; height: 793px; margin: 0px auto; width: 320px;"></p> + +<p>개선책은 좁은 화면에서 사이트를 볼 때 이미지의 중요한 상세를 보여 주는 자른 이미지를 보여 주는 것이다. 또 다르게 자른 이미지를 태블릿처럼 중간 정도 너비 화면의 기기에서 보여줄 수 있을 것이다. 이를 보통 <strong>아트 디렉션 문제(art direction problem)</strong>라고 한다. [아트 디렉션은 ‘연출 방향’ 정도로 번역할 수 있을 듯한데, 보통은 용어를 그대로 사용한다. 반응형 이미지에서는 이미지의 의도가 제대로 전달되도록 기기에 따라 사진의 핵심을 확대해서 보여 주거나 하는 방식을 의미한다. - 역자 주]</p> + +<p>게다가, 작은 모바일 화면에서는 페이지에 그렇게 큰 이미지를 포함할 필요가 없다. 이것을 <strong>해상도 전환 문제(resolution switching problem)</strong>라고 부른다. <a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Adding_vector_graphics_to_the_Web">벡터 그래픽 단원</a>에서 배웠듯이, 래스터 이미지[비트맵 이미지 - 역자 주]는 가로 픽셀들과 세로 픽셀들의 세트로 구성된다. 작은 래스터 이미지를 실제 사이즈보다 확대해서 보면 도트가 깨져 보인다(벡터 그래픽은 그렇지 않은데 반해).</p> + +<p>역으로, 적당한 크기보다 훨씬 작은 화면에 큰 이미지를 표시 할 필요가 없다. 그렇게 하는 것은 대역폭을 낭비하는 것이다. 특히, 모바일 사용자는 기기에 맞는 작은 이미지 대신 데스크톱에 사용되는 커다른 이미지를 다운로드하느라 대역폭을 낭비하고 싶어하지 않는다. 이상적인 상황은 다양한 해상도를 준비해 두고, 웹사이트 데이터를 받는 기기에 따라 적당한 사이즈를 제공하는 것이다.</p> + +<p>상황을 좀더 복잡하게 하면, 어떤 기기는 고해상도 화면이 있어서, 멋지게 보이려면 더 큰 이미지가 필요하다. 이것은 근본적으로 같은 문제지만, 약간 맥락은 다르다.</p> + +<p>아마 벡터 이미지가 이 문제를 해결할 것이라고 생각할 지도 모르겠고, 실제로 어느 정도는 그렇기도 하다 — 벡터 이미지는 파일 사이즈도 작고 확대해도 깨지지 않는다. 사용할 수 있다면 언제나 사용해야 한다. 그러나 벡터 이미지가 모든 유형에 맞는 것은 아니다. 간단한 그래픽, 패턴, 인터페이스 요소 등에 적합하지만, 사진 같은 상세한 종류의 이미지를 벡터 기반으로 만들려고 하면 복잡해지기 시작한다. JPEG 같은 래스터 이미지 포맷은 위 예제에 나온 종류의 이미지에 더 적합하다.</p> + +<p>이런 종류의 문제는 90년대 초중반에 웹이 처음 등장했을 때는 존재하지 않았다. 당시 웹을 탐색할 수 있는 기기는 데스크톱과 노트북뿐이었기 때문에 브라우저 개발자와 명세 작성자는 해결책 구현에 대한 생각조차 하지 않았다. 브라우저에 여러 개의 이미지 파일들을 제공하는 <em>반응형 이미지 기술</em>은 위에서 지적한 문제를 해결하기 위해 최근에 구현됐다. 픽셀 수가 다르지만 동일한 이미지를 보여주거나(<em>해상도 전환</em>), 다른 공간 점유에 맞는 다른 이미지를 보여 주거나(<em>아트 디렉션</em>).</p> + +<div class="note"> +<p><strong>알림</strong>: 이 글에서 다루는 새로운 기능들 — {{htmlattrxref("srcset", "img")}}/{{htmlattrxref("sizes", "img")}}/{{htmlelement("picture")}} — 은 모두 출시된 최신 데스크톱과 모바일 브라우저(인터넷 익스플로러는 구현이 안 돼 있지만, 마이크로소프트 엣지를 포함해)에서 지원된다. </p> +</div> + +<h2 id="반응형_이미지를_어떻게_만들까">반응형 이미지를 어떻게 만들까?</h2> + +<p>이 섹션에서는 위에서 설명한 두 가지 문제를 살펴보고 HTML 반응형 이미지 기법을 이용해 문제를 해결하는 방법을 보여 준다. 이 섹션에서는, 위 예제의 본문 영역에서 봤듯, HTML {{htmlelement("img")}}에 초점을 맞출 것이라는 점을 주목하기 바란다(헤더 이미지는 장식용이고, 따라서 CSS 배경 이미지로 구현됐다). <a href="http://blog.cloudfour.com/responsive-images-101-part-8-css-images/">CSS에는 분명 HTML보다 더 나은 반응형 디자인 도구</a>가 있고, 그것은 향후 CSS 모듈에서 다룰 것이다.</p> + +<h3 id="해상도_전환_다양한_사이즈">해상도 전환: 다양한 사이즈</h3> + +<p>자, 해상도 전환으로 해결하려고 하는 문제는 뭘까? 우리는 기기에 따라 단지 크기만 다른, 동일한 이미지 콘텐츠를 보여 주고 싶다. 우리 예제에서 본문 두 번째 이미지가 직면한 상황이다. 표준 {{htmlelement("img")}} 요소는 전통적으로 브라우저에게 오직 하나의 소스 파일만 제시하도록 돼 있었다.</p> + +<pre class="brush: html notranslate"><img src="elva-fairy-800w.jpg" alt="요정 옷을 입은 엘바"></pre> + +<p>그러나 {{htmlattrxref("srcset", "img")}}과 {{htmlattrxref("sizes", "img")}}라는 두 가지 새로운 속성(attribute)을 사용해 브라우저가 올바른 것을 선택하는 데 도움이 되는 몇 가지 추가 소스 이미지와 힌트를 제공 할 수 있다. 이 예제는 Github의 <a href="http://mdn.github.io/learning-area/html/multimedia-and-embedding/responsive-images/responsive.html">responsive.html</a> 예제 (<a href="https://github.com/mdn/learning-area/blob/master/html/multimedia-and-embedding/responsive-images/responsive.html">소스 코드</a> 참조)에서 볼 수 있다.</p> + +<pre class="brush: html notranslate"><img srcset="elva-fairy-320w.jpg 320w, + elva-fairy-480w.jpg 480w, + elva-fairy-800w.jpg 800w" + sizes="(max-width: 320px) 280px, + (max-width: 480px) 440px, + 800px" + src="elva-fairy-800w.jpg" alt="요정 옷을 입은 엘바"></pre> + +<p><code>srcset</code>과 <code>sizes</code> 속성은 복잡해 보이지만 위에서 보여 준 것처럼 각 행에 속성 값을 나눠 적으면 이해하기 어렵지 않다. 각 값은 쉼표로 구분한 목록으로 적고, 목록의 각 부분은 세 부분으로 구성된다. 이제 각 내용을 살펴 보자.</p> + +<p><strong><code>srcset</code></strong>은 브라우저에게 제시할 이미지 목록과 그 크기를 정의한다. 각 쉼표 앞에 이렇게 적는다.</p> + +<ol> + <li><strong>이미지 파일명</strong> (<code>elva-fairy-480w.jpg</code>.)</li> + <li>공백</li> + <li>이미지 <strong>고유 픽셀 너비</strong> (<code>480w</code>) — <code>px</code>이 아니라 <code>w</code> 단위를 사용한다는 데 주의하라. 이것은 이미지의 실제 사이즈인데, 컴퓨터에서 이미지를 확인하면 찾을 수 있다. (예컨대, 맥에서는 파인더에서 이미지를 선택하고 <kbd>Cmd</kbd> + <kbd>I</kbd>를 눌러 정보를 표시 할 수 있다).</li> +</ol> + + + +<p><strong><code>sizes</code></strong>는 미디어 조건문들을 정의하고(예를 들면, 화면 크기) 특정 미디어 조건문이 참일 때 어떤 이미지 크기가 최적인지 나타낸다(앞서 언급한 힌트). 이 경우, 각 쉼표 전에 이렇게 쓴다.</p> + +<ol> + <li><strong>미디어 조건문</strong> (<code>(max-width:480px)</code>) — CSS 주제에서 이에 대해 더 많은 것을 배울 수 있을 테지만, 지금 간단히 말하면, 미디어 조건문은 가능한 화면 상태를 기술한다. 이 경우, 이렇게 말하는 것이다: “뷰포트 너비가 480픽셀 이하”.</li> + <li>공백.</li> + <li>미디어 조건문이 참인 경우 이미지가 채울 <strong>슬롯의 너비</strong>(<code>440px</code>).</li> +</ol> + +<div class="note"> +<p><strong>알림</strong>: 슬롯 너비로 절대값(<code>px</code>, <code>em</code>)이나 뷰포트에 대한 상대값(<code>vw</code>)을 넣어야 한다. 상대값으로 퍼센트(<code>%</code>)를 넣을 수는 없다. 마지막 슬롯 너비에는 미디어 조건문이 없다는 것을 확인했을 것이다. 이것은 미디어 조건문이 참인 경우가 하나도 없는 것우의 기본값이다. 브라우저는 첫 번째 조건문이 맞으면 나머지 모든 조건문을 무시한다. 따라서 미디어 조건문의 순서에 유의하라.</p> +</div> + +<p>그래서, 이 속성들을 제대로 적으면, 브라우저는 이렇게 할 것이다.</p> + +<ol> + <li>기기 너비를 확인한다.</li> + <li><code>sizes</code> 목록에서 가장 먼저 참이 되는 미디어 조건문을 확인한다.</li> + <li>해당 미디어 쿼리가 제공하는 슬롯 크기를 확인한다.</li> + <li>해당 슬롯 크기에 가장 근접하게 맞는 <code>srcset</code>에 연결된 이미지를 불러온다.</li> +</ol> + +<p>이게 전부다! 그래서 지금, 이 속성을 지원하는 뷰포트 너비가 480px인 브라우저가 페이지를 불러온다고 하자, <code>(max-width: 480px)</code> 미디어 조건문이 참이 될 것이고, 따라서 <code>440px</code> 슬롯이 선택될 것이다. 그러면 <code>440px</code>에 가장 가까운 고유 너비(<code>480w</code>)가 선택됨에 따라 <code>elva-fairy-480w.jpg</code>가 로딩될 것이다. 800px 사진은 128KB다. 480px 버전은 고작 63KB인데 말이다. 65KB를 절약했다. 사진이 엄청 많은 페이지였다면 어땠을까. 이 기법은 모바일 사용자가 수많은 대역폭을 절약하게 해 준다.</p> + +<p>이 기능을 지원하지 않는 낡은 브라우저들은 이 속성들을 무시할 것이다. 그리고 {{htmlattrxref("src", "img")}} 속성에 참조된 보통 이미지를 불러올 것이다.</p> + +<div class="note"> +<p><strong>알림</strong>: 문서의 {{htmlelement("head")}}에서 <code><meta name="viewport" content="width=device-width"></code> 줄을 찾을 수 있을 것이다. 이것은 모바일 브라우저가 실제 뷰포트 너비로 웹페이지를 보여주도록 강제한다. (몇몇 모바일 브라우저들은 뷰포트 너비를 속인다, 그리고 대신에 더 큰 뷰포트 너비에서 페이지를 불러오고, 불러온 페이지를 축소한다. 이것은 반응형 이미지나 디자인에 별로 도움이 되지 않는다. 이것에 대해서는 향후 더 자세히 다룰 것이다.)</p> +</div> + +<h3 id="유용한_개발_도구">유용한 개발 도구</h3> + +<p>브라우저에는 필요한 슬롯 너비, 기타, 필요한 것들을 찾을 수 있게 도와 주는 유용한 <a href="https://developer.mozilla.org/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">개발 도구들</a>이 있다. 나는 우선 반응형이 아닌 일반 버전의 예제를 불러온다(<code>not-responsive.html</code>). 그리고 나서 <a href="https://developer.mozilla.org/en-US/docs/Tools/Responsive_Design_Mode">반응형 디자인 모드</a>(도구 > 웹 개발 도구 > 반응형 디자인 모드)로 간다. 이 모드는 다양한 크기의 기기로 보는 것처럼 웹페이지 레이아웃을 보게 해 준다.</p> + +<p>나는 뷰포트 너비를 320px로 했다가 480px로 한다. 각 너비에서 나는 <a href="https://developer.mozilla.org/ko/docs/%EB%8F%84%EA%B5%AC%EB%93%A4/Page_Inspector">DOM 검사기</a>로 가서, 확인하고 싶은 {{htmlelement("img")}} 요소를 클릭한다. 그리고 화면의 오른쪽에 있는 박스 모델 뷰 탭에서 크기를 확인한다. 이렇게 하면 필요한 고유 너비를 알 수 있다.</p> + +<p><img alt="A screenshot of the firefox devtools with an image element highlighted in the dom, showing its dimensions as 440 by 293 pixels." src="https://mdn.mozillademos.org/files/12932/box-model-devtools.png" style="display: block; height: 845px; margin: 0px auto; width: 480px;"></p> + +<p>다음으로 원하는 뷰포트 너비를 설정해서 어떤 <code>srcset</code>이 작동하는지 체크할 수 있다(예컨대, 좁게 설정할 수 있다). 네트워크 검사기(도구 > 웹 개발 도구 > 네트워크)를 열고, 페이지를 새로 고침 한다. 웹페이지를 만들기 위해 다운로드한 항목들을 보여 주는데, 따라서 어떤 이미지가 사용됐는지 여기서 확인할 수 있다.</p> + +<div class="note"> +<p><strong>알림:</strong> 크롬에서 테스트할 때 캐시를 비활성화하라. 개발자 도구를 열고, <strong>Network</strong> 탭의 체크박스들 중 <strong>Disable cache</strong>에 체크하라. 이렇게 하지 않으면 크롬은 최적의 이미지보다 캐시된 이미지를 선호할 것이다.</p> +</div> + +<p><img alt="a screenshot of the network inspector in firefox devtools, showing that the HTML for the page has been downloaded, along with three images, which include the two 800 wide versions of the responsive images" src="https://mdn.mozillademos.org/files/12934/network-devtools.png" style="display: block; height: 630px; margin: 0px auto; width: 600px;"></p> + +<h3 id="해상도_전환_같은_크기_다른_해상도">해상도 전환: 같은 크기, 다른 해상도</h3> + +<p>만약 다양한 디스플레이 해상도를 지원해야 하는데, 모두가 이미지를 실제 사이즈로 동일하게 봐야 한다면, <code>srcset</code>에 <code>sizes</code> 없이 x-서술자를 사용해 브라우저가 적절한 해상도의 이미지를 선택하게 할 수 있다. 꽤 쉽다. <a href="http://mdn.github.io/learning-area/html/multimedia-and-embedding/responsive-images/srcset-resolutions.html">srcset-resolutions.html</a>에서 예제를 찾아 볼 수 있다. (<a href="https://github.com/mdn/learning-area/blob/master/html/multimedia-and-embedding/responsive-images/srcset-resolutions.html">소스 코드</a>도 볼 수 있다.)</p> + +<pre class="brush: html notranslate"><img srcset="elva-fairy-320w.jpg, + elva-fairy-480w.jpg 1.5x, + elva-fairy-640w.jpg 2x" + src="elva-fairy-640w.jpg" alt="요정 옷을 입은 엘바"> +</pre> + +<p><img alt="A picture of a little girl dressed up as a fairy, with an old camera film effect applied to the image" src="https://mdn.mozillademos.org/files/12942/resolution-example.png" style="display: block; height: 425px; margin: 0px auto; width: 480px;">이 예에서, 다음 CSS가 이미지에 적용되고, 따라서 화면에서 너비는 320px이 된다(CSS 픽셀이라고 부르기도 한다).</p> + +<pre class="brush: css notranslate">img { + width: 320px; +}</pre> + +<p>이 경우 sizes는 필요 없다. 브라우저는 단순히 보이는 해상도가 얼마인지는 확인하고 <code>srcset</code>에 참조돼 있는 것들 중 가장 적합한 이미지를 제공한다. 따라서 기기의 1픽셀이 CSS의 1필셀에 대응되는, 보통/낮은 해상도 디스플레이의 기기가 페이지에 접속하면, <code>elva-fairy-320w.jpg</code>가 로드될 것이다(1x가 적용됐고, 그걸 명시해서 적을 필요는 없다). 만약 기기의 2픽셀이 CSS 1픽셀에 해당하는 고해상도 기기라면, <code>elva-fairy-640w.jpg</code>가 로드될 것이다. 640px 이미지는 93KB다. 320px 이미지는 39KB밖에 안 된다.</p> + +<h3 id="아트_디렉션">아트 디렉션</h3> + +<p>다시 말하면, <strong>아트 디렉션 문제</strong>는 서로 다른 이미지 디스플레이 사이즈에 맞추기 위해 디스플레이된 이미지를 변경하고자 하는 것과 관련있다. 예를 들면, 웹사이트에 데스크톱 브라우저로 들어오면 가운데 한 사람이 있는 커다란 가로 사진이 있다. 그런데 모바일 브라우저로 줄여서 보면 사람이 보기 힘들 정도로 정말 작아진다. 사람이 확대된 좀더 작은 세로 사진으로 보여 주는 게 더 나을 것이다. {{htmlelement("picture")}} 요소가 이런 종류의 해결책을 구현하게 해 준다.</p> + +<p>원래의 <a href="http://mdn.github.io/learning-area/html/multimedia-and-embedding/responsive-images/not-responsive.html">not-responsive.html</a> 예제로 돌아가 보자. 아트 디렉션이 절실히 필요한 사진이 있다.</p> + +<pre class="brush: html notranslate"><img src="elva-800w.jpg" alt="딸 엘바를 안고 서 있는 크리스"></pre> + +<p>{{htmlelement("picture")}}를 이용해 고쳐 보자! <a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Video_and_audio_content"><code><video></code>와 <code><audio></code></a> 처럼, <picture> 요소는 {{htmlelement("source")}} 요소들을 감싼다. <code>source</code> 요소는 브라우저가 고를 수 있는 여러 소스들을 제공한다. <code>soucre</code> 요소들 뒤에는 가장 중요한 {{htmlelement("img")}} 요소가 뒤따른다. <a href="http://mdn.github.io/learning-area/html/multimedia-and-embedding/responsive-images/responsive.html">responsive.html</a> 코드는 이렇다.</p> + +<pre class="brush: html notranslate"><picture> + <source media="(max-width: 799px)" srcset="elva-480w-close-portrait.jpg"> + <source media="(min-width: 800px)" srcset="elva-800w.jpg"> + <img src="elva-800w.jpg" alt="딸 엘바를 안고 서 있는 크리스"> +</picture> +</pre> + +<ul> + <li><code><source></code> 요소에는 미디어 조건문이 있는 <code>media</code> 속성이 있다 — 처음에 살펴 봤던 <code>srcset</code> 예제처럼, 이 조건들도 어떤 이미지를 보여 줄 지 결정하는 데 사용한다 — 참을 리턴하는 첫 번째 것이 표시된다. 이 경우, 만약 뷰포트 너비가 799px 이하라면, 첫 번째 <code><source></code> 요소의 이미지가 표시될 것이다. 만약 뷰포트 너비가 800px 이상이라면, 두 번째 것을 보여 줄 것이다.</li> + <li>srcset 속성에는 보여 줄 이미지 경로가 있었다. 위의 <code><img></code>에서 살펴 봤듯이, <code><source></code>도 여러 참조 이미지와 <code>sizes</code> 속성을 <code>srcset</code> 속성에 넣을 수 있다. 따라서 우리는 이미지 여러 개를 <code><picture></code> 요소에서 제공할 수 있다. 하지만 그렇게 되면 각각 다양한 해상도도 제공해야 할 것이다. 현실적으로, 이런 일을 자주 하고 싶지는 않을 것이다.</li> + <li>이 모든 경우, <code>src</code>와 <code>alt</code> 속성이 있는 <code><img></code> 요소를 <code></picture></code> 바로 앞에 반드시 제공해야 한다. 그렇지 않으면 이미지가 표시되지 않을 것이다. 이것은 참을 리턴하는 미디어 조건문이 없는 경우 기본 이미지를 제공하는 것이다(실제 이 예제에서 두 번째 <code><source></code> 요소는 제거해도 된다). 그리고 <picture> 요소를 지원하지 않는 브라우저에 대체제를 제공하는 것이기도 하다.</li> +</ul> + +<p>이 코드는 넓은 화면과 좁은 화면 둘 다에서 적절한 이미지를 표시하게 해 준다. 아래를 보자.</p> + +<p><img alt="Our example site as viewed on a wide screen - here the first image works ok, as it is big enough to see the detail in the center." src="https://mdn.mozillademos.org/files/12940/picture-element-wide.png" style="display: block; height: 554px; margin: 0px auto; width: 700px;"><img alt="Our example site as viewed on a narrow screen with the picture element used to switch the first image to a portrait close up of the detail, making it a lot more useful on a narrow screen" src="https://mdn.mozillademos.org/files/12938/picture-element-narrow.png" style="display: block; height: 710px; margin: 0px auto; width: 320px;"></p> + +<div class="note"> +<p><strong>알림</strong>: 미디어 속성은 아트 디렉션 시나리오에서만 사용하라. 만약 미디어를 사용한다면, 미디어 조건문을 사이즈 속성에 넣지 마라.</p> +</div> + +<h3 id="왜_CSS나_자바스크립트를_이용해_이렇게_할_수_없는가">왜 CSS나 자바스크립트를 이용해 이렇게 할 수 없는가?</h3> + +<p>브라우저가 페이지를 불러오기 시작할 때, 메인 파서가 CSS와 자바스크립트를 로드하고 해석하기 전에 이미지들을 다운로드(미리 불러오기)하기 시작한다. 이렇게 하는 것은 평균적으로 페이지 로딩 시간을 20%쯤 단축시켜주는 유용한 기법이다. 그러나 반응형 이미지에는 도움이 안 된다. 따라서 <code>srcset</code> 같은 해결책을 구현해야 한다. 예를 들면, {{htmlelement("img")}} 요소를 불러온 후, 자바스크립트로 뷰포트 너비를 감지하고, 필요하면 더 작은 소스 이미지로 동적으로 바꾸는 식으로 할 수 없다. 그 시점에, 원래의 이미지가 이미 로드된 상태고, 작은 이미지까지 불러와야 한다. 반응형 이미지 관점에서 더 나쁘다.</p> + +<ul> +</ul> + +<h3 id="최신_이미지_포맷을_대담하게_사용하라">최신 이미지 포맷을 대담하게 사용하라</h3> + +<p>흥미로운 새 이미지 포맷들이 있다(WebP나 JPEG-2000). 이 포맷들은 작은 용량과 높은 질을 동시에 유지할 수 있게 해 준다. 그러나 브라우저 지원에 구멍이 많다.</p> + +<p><code><picture></code>는 상대적으로 낡은 브라우저들의 욕구도 채워 준다. 우리는 <code>type</code> 속성 안에 마임타입을 제공해 브라우저가 지원하지 않는 파일 유형을 즉시 거부하도록 할 수 있다.</p> + +<pre class="brush: html notranslate"><picture> + <source type="image/svg+xml" srcset="pyramid.svg"> + <source type="image/webp" srcset="pyramid.webp"> + <img src="pyramid.png" alt="정삼각형 4개로 만든 일반적인 피라미드"> +</picture> +</pre> + +<ul> + <li>아트 디렉션이 필요한 경우가 아니라면 <code>media</code> 속성을 사용하지 마라.</li> + <li><code><source></code> 요소에서, <code>type</code>에 유형을 선언한 이미지만 사용할 수 있다.</li> + <li>앞서 다뤘듯, 필요에 따라 <code>srcset</code>과 <code>sizes</code>에 쉼표로 구분한 목록을 얼마든 사용할 수 있다.</li> +</ul> + +<h2 id="능동적_학습_나만의_반응형_이미지_구현">능동적 학습: 나만의 반응형 이미지 구현</h2> + +<p>능동적 학습을 위해, 우리는 당신이 용기를 내 홀로 해 보길 기대한다. (... 대개는.) 우리는 당신이 <code><picture></code>를 이용해 자신만의 딱 맞는 좁은 화면용/넓은 화면용 아트 디렉션 샷을 구현하고, <code>srcset</code>을 사용하는 해상도 전환 예제를 구현하길 바란다.</p> + +<ol> + <li>자기 코드가 있는 간단한 HTML을 작성하라(원한다면 <code>not-responsive.html</code>를 시작점으로 삼자).</li> + <li>어딘가에 상세한 부분이 있는 멋진 가로 풍경 사진을 찾아라. 그래픽 편집기를 이용해 웹 사이즈 버전을 만들고, 상세한 부분을 확대해 보여줄 수 있도록 그걸 더 작게 잘라서 두 번째 이미지를 만들자(대략 480px 정도면 적당하다).</li> + <li><code>srcset</code>/<code>size</code>를 사용해, 서로 다른 해상도에서 같은 크기의 이미지를 제공하거나 서로 다른 뷰포트 너비에서 서로 다른 크기 이미지를 제공하는 해상도 전환 예제를 만들자.</li> +</ol> + +<div class="note"> +<p><strong>알림</strong>: 위에서 보여 줬듯이, 브라우저 개발자 도구를 사용해 필요한 크기가 얼마인지 찾아내는 데 도움을 얻자.</p> +</div> + +<h2 id="정리">정리</h2> + +<p>이것이 반응형 이미지의 비밀이다. 이 새로운 기법을 즐기길 바란다. 핵심을 되짚다면, 우리가 다룬 두 가지 구분된 문제가 있다.</p> + +<ul> + <li><strong>아트 디렉션</strong>: 다양한 레이아웃에 자른 이미지를 제공하고자 하는 문제. 예를 들면, 데스크톱 레이아웃에서 전체 풍경을 보여 주는 가로 이미지와 모바일 레이아웃에서 주요 대상을 좀더 가깝게 확대해서 보여 주는 세로 이미지. {{htmlelement("picture")}} 요소를 이용해 해결할 수 있다.</li> + <li><strong>해상도 전환</strong>: 데스크톱 디스플레이와 달리 커다란 이미지가 필요치 않은 좁은 화면 기기에 더 작은 이미지 파일을 제공하고자 하는 문제. 그리고 또한 선택적으로 다양한 해상도 이미지를 고밀도/저밀도 화면에 제공하고자 하는 문제. 이것은 <a href="/ko/docs/Learn/HTML/Multimedia_and_embedding/Adding_vector_graphics_to_the_Web">벡터 그래픽</a>(SVG 이미지), {{htmlattrxref("srcset", "img")}}와 {{htmlattrxref("sizes", "img")}} 속성을 이용해 해결할 수 있다.</li> +</ul> + +<p>이것으로 전체 <a href="/ko/docs/Learn/HTML/Multimedia_and_embedding">멀티미디어와 엠베딩</a> 모듈을 끝냈다! 남은 것은 멀티미디어 평가를 치르는 것뿐이다. 얼마나 배웠는지 확인해 보자. 즐겁게 진행하기를!</p> + +<h2 id="더_알아_보기">더 알아 보기</h2> + +<ul> + <li><a href="http://blog.cloudfour.com/responsive-images-101-definitions">제이슨 그릭스비의 훌륭한 반응형 이미지 소개</a></li> + <li><a href="https://css-tricks.com/responsive-images-youre-just-changing-resolutions-use-srcset/">반응형 이미지: 해상도를 변경할 뿐이라면, srcset을 사용하라</a> — 브라우저가 어떤 이미지를 사용할지 고르는 방법에 대한 더 상세한 설명 포함</li> + <li>{{htmlelement("img")}}</li> + <li>{{htmlelement("picture")}}</li> + <li>{{htmlelement("source")}}</li> +</ul> + +<div>{{PreviousMenuNext("Learn/HTML/Multimedia_and_embedding/Adding_vector_graphics_to_the_Web", "Learn/HTML/Multimedia_and_embedding/Mozilla_splash_page", "Learn/HTML/Multimedia_and_embedding")}}</div> + +<div> +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/ko/docs/Learn/HTML/Multimedia_and_embedding/Images_in_HTML">HTML의 이미지</a></li> + <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Video_and_audio_content">Video and audio content</a></li> + <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Other_embedding_technologies">From <object> to <iframe> — other embedding technologies</a></li> + <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Adding_vector_graphics_to_the_Web">Adding vector graphics to the Web</a></li> + <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images">Responsive images</a></li> + <li><a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Mozilla_splash_page">Mozilla splash page</a></li> +</ul> +</div> diff --git a/files/ko/learn/html/tables/index.html b/files/ko/learn/html/tables/index.html new file mode 100644 index 0000000000..72964f0907 --- /dev/null +++ b/files/ko/learn/html/tables/index.html @@ -0,0 +1,42 @@ +--- +title: HTML tables +slug: Learn/HTML/Tables +tags: + - HTML + - 가이드 + - 모듈 + - 초보자 + - 테이블 +translation_of: Learn/HTML/Tables +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">HTML에서 매우 일반적인 작업으로 표 형식의 데이터를 구조화하는 것이며, 이 목적을 위해 여러 요소와 속성을 가지고 있습니다. 스타일링을 위해 약간의 CSS 와 HTML을 함께 사용하면 학교 수업 계획, 지역 수영장 시간표 또는 좋아하는 공룡이나 축구 팀 통계와 같은 웹 테이블 정보를 쉽게 표시 할 수 있습니다. 이 모듈은 HTML을 사용하여 표 형식의 데이터를 구성하는데 필요한 모든 정보를 제공 합니다.</p> + +<h2 id="전제조건">전제조건</h2> + +<p>이 모듈을 시작하기 전에, 당신은 이미 HTML의 기본 지식을 가지고 있어야 합니다. — <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">Introduction to HTML</a>.</p> + +<div class="note"> +<p><strong>노트</strong>: 컴퓨터/태블릿/기타 장치에서 자신만의 파일들을 생성 할 수 없다면, 대부분의 예제 코드는 <a href="http://jsbin.com/">JSBin</a> 또는 <a href="https://thimble.mozilla.org/">Thimble</a> 같은 온라인 코딩 프로그램에서 시도해 볼 수 있습니다.</p> +</div> + +<h2 id="가이드">가이드</h2> + +<p>이 모듈은 다음의 내용을 담고 있습니다.</p> + +<dl> + <dt><a href="/ko/docs/Learn/HTML/Tables/Basics">HTML 테이블 기본</a></dt> + <dd>이 내용에서는 행(row)과 셀(cell), 머리말, 셀을 여러 열(col)과 행(row)으로 확장(span)하는 것과 같은 기본 사항을 다루는 HTML 표를 시작하고 스타일 지정을 위해 열의 모든 셀을 함께 그룹화하는 방법에 대해 설명합니다.</dd> + <dt><a href="/ko/docs/Learn/HTML/Tables/Advanced">HTML 테이블 고급 기능 및 접근성</a></dt> + <dd> + <p>이 모듈의 두 번째 내용에서는 HTML 테이블의 캡션/요약 및 행을 테이블 머리, 본문 및 바닥글 세션으로 그룹화 하는 것과 같은 몇 가지 고급 기능을 살펴볼 뿐만 아니라 시각 장애가 있는 사용자를 위한 테이블의 접근성도 살펴보게 됩니다.</p> + </dd> +</dl> + +<h2 id="평가">평가</h2> + +<dl> + <dt><a href="/ko/docs/Learn/HTML/Tables/Structuring_planet_data">행성 데이터 구성</a></dt> + <dd>우리의 테이블 평가에서 태양계의 행성에 대한 데이터 일부를 당신에게 제공하며, 그것을 가지고 HTML 테이블로 구성 하도록 합니다.</dd> +</dl> diff --git a/files/ko/learn/index.html b/files/ko/learn/index.html new file mode 100644 index 0000000000..ce9e422ff5 --- /dev/null +++ b/files/ko/learn/index.html @@ -0,0 +1,167 @@ +--- +title: Web 개발 학습하기 +slug: Learn +tags: + - Beginner + - CSS + - HTML + - Index + - Intro + - Landing + - Learn + - Web + - 웹 + - 초보자 + - 학습 +translation_of: Learn +--- +<div>{{LearnSidebar}}</div> + +<div> +<p class="summary">환영합니다! 이곳에서 다루는 문서들은 웹개발을 처음 접하는 초보자를 대상으로 합니다. 그리고 간단한 웹사이트를 만들기 위해 필요한 모든 것들을 담고 있습니다.</p> +</div> + +<p>여기에서는 여러분을 "초보자"에서 "전문가"로 이끄는 걸 목표로 하지 않습니다. 다만, 여러분을 "초보자"에서 "익숙한 단계"로 이끄는 걸 목표로 합니다. 그 이후에는 자신만의 스타일을 찾아야만 합니다. 그리고 그때 보게 될 <a href="https://developer.mozilla.org/ko">MDN의 나머지 문서들</a>이나 다른 문서들은 많은 사전지식을 필요로 할 것입니다.<br> + <br> + 코딩을 처음 접하는 분들에게 웹개발은 어려울 수 있습니다(그렇지만 저희가 최선을 다해 설명해드릴께요!). 그렇지만 당신이 웹 개발을 배우고 싶은 학생이든, 수업 자료를 찾는 선생님이든, 그리고 취미로 웹기술을 알고 싶은 사람이든 상관없이 편하게 공부할 수 있도록 하겠습니다.</p> + +<h2 id="새로운_콘텐츠">새로운 콘텐츠?</h2> + +<p>이 곳의 내용은 정기적으로 추가되고 있습니다. 변경점을 추적하기 위해 <a href="/en-US/docs/Learn/Release_notes">Learning area release note</a>를 관리하기 시작했으니, 정기적으로 확인해주세요!</p> + +<p>원하는 주제나 빠진 것 같은 부분에 대한 질문은 저희의 <a href="https://discourse.mozilla.org/c/mdn">Discourse 포럼</a>에 남겨주세요.</p> + +<h2 id="어디서_시작해야_하나">어디서 시작해야 하나</h2> + +<ul class="card-grid"> + <li><span>완전 초보라면</span> + + <p> 웹개발을 처음 하신다면 <a href="/ko/docs/Learn/Getting_started_with_the_web" style="background-color: rgba(234, 239, 242, 0.498039);">"웹 개발 시작하기"</a> 를 추천합니다. 웹 개발에 대한 실용적인 정보를 제공하고 있습니다.</p> + </li> + <li><span>질문이 있으면</span> + <p>웹개발에 대한 질문은 <a href="/ko/docs/Learn/Common_questions">Common question</a>를 살펴보시길 바랍니다. 도움이 될만한 정보가 있을 것입니다.</p> + </li> + <li><span>초보적인 지식에서 나아가기</span> + <p>초보 개발자에서 한 단계 더 나아가고 싶다면 {{glossary("HTML")}} 과 {{glossary("CSS")}} 를 상세히 배워보세요. <a href="/ko/docs/Learn/HTML/Introduction_to_HTML">HTML</a>, <a href="/ko/docs/Learn/CSS/Introduction_to_CSS">CSS</a>에 대한 소개를 배울 수 있습니다.</p> + </li> + <li><span>스크립트 다루기</span> + <p><span>HTML과 CSS을 잘 다루거나 코딩 경험이 많다면, </span>{{glossary("JavaScript")}}나 서버측 개발을 해 보시는 것이 좋습니다. <a href="/ko/docs/Learn/JavaScript/First_steps">JavaScript시작하기</a>와 <a href="/ko/docs/Learn/Server-side/First_steps">서버측 개발 시작하기</a>를 시작해 보세요.</p> + </li> +</ul> + +<div class="note"> +<p><strong>참고</strong>: 기술 정의에 대한 <a href="/ko/docs/Glossary">용어집</a>를 제공합니다. </p> +</div> + +<p>{{LearnBox({"title":"Random glossary entry"})}}</p> + +<h2 id="다루는_주제">다루는 주제</h2> + +<p>다음은 MDN 학습 영역에서 다루는 모든 주제의 목록입니다.</p> + +<dl> + <dt><a href="/ko/docs/Learn/Getting_started_with_the_web">웹 개발 시작하기</a></dt> + <dd>초보자가 쉽게 따라할 수 있도록 웹 개발을 간단히 소개합니다.</dd> + <dt><a href="/ko/docs/Learn/HTML">HTML — 웹 구축하기</a></dt> + <dd>HTML은 웹사이트에 들어갈 내용을 작성하고, 해당 내용이 의미나 목적을 정의할 때 사용하는 언어입니다. 이 곳에서는 HTML을 자세히 설명합니다.</dd> + <dt><a href="/ko/docs/Learn/CSS">CSS — 웹 스타일링 익히기</a></dt> + <dd>CSS는 웹을 꾸미는 데 사용합니다. 애니메이션과 같은 동작을 추가하거나 웹 컨텐츠의 스타일을 지정할 때 사용할 수 있습니다. 이 곳을 통해 CSS 활용법을 알 수 있습니다.</dd> + <dt><a href="/ko/docs/Learn/JavaScript">JavaScript — 동적인 클라이언트 사이드(혹은 프론트 엔드) 언어</a></dt> + <dd>JavaScript는 동적 기능을 웹 페이지에 넣을 때 사용하는 스크립트 언어입니다. 이 문서는 JavaScript를 이해하고 작성하는데 익숙해지는데 필요한 핵심적인 내용을 모두 가르쳐줍니다.</dd> + <dt><a href="/ko/docs/Learn/Forms">Web forms — 사용자 데이타로 작업하기</a></dt> + <dd>Web forms는 사용자와 정보를 주고받기 위한 강력한 도구입니다 — 주로 사용자의 정보를 수집하거나, 유저 인터페이스를 제공하기 위해 사용됩니다. 관련 문서에서 web 폼을 구성하고, 꾸미고, web form과 통신하기 위해 필요한 핵심적인 내용을 모두 다룹니다.</dd> + <dt><a href="/ko/docs/Learn/Accessibility">접근성 — 모두를 위한 웹사이트</a></dt> + <dd>접근성은 신체적인 장애나 지역과 장비및 기타 개인간 차별을 유발하는 요소에 상관없이 누구나 웹에 접근할 수 있도록 하기 위한 코드 작성법을 다룹니다. 이 문서를 통해 필요한 모든 내용을 학습할 수 있습니다.</dd> + <dt><a href="/ko/docs/Learn/Performance">Web 성능 — 웹사이트를 빠르고 즉시 반응하도록 만들기 </a></dt> + <dd>Web 성능은 사용자의 인터넷 대역이나, 화면 크기, 네트워크나 장비의 능력에 관계없이, 웹 어플리케이션의 다운로드를 빠르게하고 사용자의 조작에 즉시 반응하도록 하는 기술입니다. </dd> + <dt><a href="/ko/docs/Learn/Tools_and_testing">도구와 테스트</a></dt> + <dd>크로스 브라우징(cross browsing) 도구처럼 개발자가 개발을 하는 데 도움을 주는 도구를 설명합니다.</dd> + <dt><a href="/ko/docs/Learn/Server-side">서버 사이드(혹은 벡 엔드) 웹 프로그래밍</a></dt> + <dd>클라이언트측 웹 개발에 집중해도 서버가 작동하는 방식을 파악하는 것이 여전히 유용합니다. 이 곳에서는 서버측의 작동 방식 간단히 알려주고, 두가지 유명한 프레임워크인 Django(Python)과 Express (node.js)를 사용하여 서버측 응용 프로그램을 빌드하는 방법을 알려줍니다.</dd> +</dl> + +<h2 id="코드_예제_얻기">코드 예제 얻기</h2> + +<p>학습 영역에서 만날 수 있는 코드 예제는 모두 <a href="https://github.com/mdn/learning-area/">GitHub에서 사용할 수 있습니다</a>. 코드 예제를 컴퓨터로 복사하고 싶다면, 가장 쉬운 방법은 <a href="https://github.com/mdn/learning-area/archive/master.zip">가장 최신의 master 코드 브랜치를 ZIP으로 다운로드</a> (<-클릭하면 zip 파일이 다운로드됨) 받는것입니다.</p> + +<p>자동 업데이트가 되는 좀더 유연한 방법으로 저장소(repo)를 복사하고 싶다면, 다음과 같이 좀 더 복잡한 과정을 따라하면 됩니다.</p> + +<ol> + <li>컴퓨터에<a href="http://git-scm.com/downloads"> Git</a>을 설치합니다. 이것은 GitHub가 사용하는 버전 관리 소프트웨어 입니다.</li> + <li><a href="https://www.lifewire.com/how-to-open-command-prompt-2618089">명령 프롬프트</a> (윈도우) 혹은 터미널(<a href="https://help.ubuntu.com/community/UsingTheTerminal">리눅스</a>, 맥<a href="http://blog.teamtreehouse.com/introduction-to-the-mac-os-x-command-line">OSX</a>)의 컴퓨터에서 엽니다.</li> + <li>명령 프롬프트/터미널이 가리키는 현재 폴더에 learning area 저장소를 복사하려면 다음 명령어를 사용하십시오: + <pre class="brush: bash">git clone https://github.com/mdn/learning-area</pre> + </li> + <li>해당 위치에 learning-area 폴더가 생성된 것을 확인할 수 있습니다.</li> +</ol> + +<p>만약 learning-area를 받은지 오래됐다면, 아래 단계를 거쳐 GitHub에서 <code>earning-area</code>에 대한 최신 정보를 업데이트 받을 수 있습니다:</p> + +<ol> + <li>명령 프롬프트/터미널에서, <code>cd</code>명령어를 사용하여 <code>learning-area</code> 디렉토리로 이동하십시오. 예를 들어 만약 상위 디렉토리에 있다면: + + <pre class="brush: bash">cd learning-area</pre> + </li> + <li>아래의 명령어를 사용하면 저장소에 있는 정보를 최신 상태로 업데이트합니다: + <pre class="brush: bash">git pull</pre> + </li> +</ol> + +<h2 id="연락처">연락처</h2> + +<p>질의 사항이 있는 경우 <a href="/ko/docs/MDN/Community/Conversations#Asynchronous_discussions">메일링 리스트</a>나 <a href="/ko/docs/MDN/Community/Conversations#Chat_in_IRC">IRC 채널</a>를 통해 메세지를 보내주실 수 있습니다. 내용 오류나 새로운 학습 주제 요청, 이해가 되지 않는 사항에 대한 질의 등 무엇이든 환영합니다.<br> + <br> + 이 모든 학습 과정은 재능 기부자들의 도움으로 만들 수 있었습니다. 컨텐츠의 개발, 개선에 대해 도움을 주실 것에 관심이 있는 경우<a href="/ko/Learn/How_to_contribute">, 도움을 주는 방법</a>을 한번 봐주시어 <a href="./docs/MDN/Community#Join_our_mailing_lists">메일링 리스트</a>나 <a href="./docs/MDN/Community#Get_into_IRC">IRC 채널</a>을 통해 소통하신다면 큰 힘이 될 것입니다. 저희는 여러분들이 필요합니다. 이 학습 플랫폼을 개선하는데 열정을 가지신 분이라면 누구든지 환영합니다.</p> + +<h2 id="관련_정보">관련 정보</h2> + +<p>** 이곳에 있던 <strong>한국어 사이트</strong>는 새로 개정되어 <strong>승인된 English (US) 버전과 동기하여 비교하기 쉽도록 </strong>아래쪽 <strong>사용자 추천 사이트</strong> 로 내렸습니다.**</p> + +<h3 id="영어_원문에_있는_사이트">영어 원문에 있는 사이트</h3> + +<dl> + <dt><a href="https://www.mozilla.org/en-US/newsletter/developer/">Mozilla Developer Newsletter</a></dt> + <dd>모든 웹 개발자를 위한 모질라 재단의 뉴스레터</dd> + <dt><a href="https://learnjavascript.online/" rel="noopener">JavaScript 배우기</a></dt> + <dd>Web 개발자 지망생을 위한 훌륭한 자료 — 짧은 강좌와 대화형 테스트, 자동화된 평가로 지도하는 인터랙티브 환경에서 JavaScript를 배웁니다. 처음 40개 강좌 는 무료이며, 한번의 작은 금액 지불로 전체코스를 수강할 수 있습니다.</dd> + <dt><a href="https://www.youtube.com/playlist?list=PLo3w8EB99pqLEopnunz-dOOBJ8t-Wgt2g">Web Demystified </a></dt> + <dd><a href="https://twitter.com/JeremiePat">Jérémie Patonnier</a>가 만든 웹 개발을 초보자가 기본을 쌓기에 좋은 강의</dd> +</dl> + +<dl> + <dt><a href="https://www.codecademy.com/">Codecademy</a></dt> + <dd>처음으로 프로그래밍 언어를 공부하고 바로 실습할 수 있음</dd> + <dt><a href="https://www.bitdegree.org/learn/">BitDegree</a></dt> + <dd>게임화를 적용한 과정으로 기초 코딩 이론을 배울수 있음. 초보자를 대상으로 함</dd> + <dt><a href="https://code.org/">Code.org</a> </dt> + <dd>기초 코딩 이론과 연습. 주로 아이들이나 완전 초보자를 대상으로 함</dd> + <dt><a href="https://exlskills.com/learn-en/courses">EXLskills</a></dt> + <dd>정보 기술을 배우는 무료 강의를 제공. 프로젝트 기반의 학습 제공되며 멘토들에게 직접 조언을 구할수도 있음</dd> + <dt><a href="https://www.freecodecamp.com/">freeCodeCamp.com</a></dt> + <dd>웹 개발을 배우기 위한 튜토리얼과 프로젝트가 있음</dd> +</dl> + +<dl> + <dt><a href="https://learning.mozilla.org/web-literacy/">Web Literacy Map</a></dt> + <dd>초보자가 웹을 활용하고 최신 기술을 배울 수 있는 사이트로 학습 활동을 위한 자료도 제공함</dd> + <dt><a href="https://edabit.com/">Edabit</a></dt> + <dd>다양한 코딩 문제를 접할 수 있음</dd> +</dl> + +<dl> + <dt> + <h3 id="영어_원문에_없는_사용자_추천_사이트">영어 원문에 없는 사용자 추천 사이트 </h3> + </dt> + <dt><a href="https://programmers.co.kr/">프로그래머스</a></dt> + <dd>프로그래밍의 기초와 실습을 동시에 할 수 있음</dd> + <dt><a href="https://opentutorials.org/course/1">생활코딩</a></dt> + <dd>웹에 대한 기초를 쌓기에 유익함</dd> + <dt><a href="https://www.edwith.org/">edwith</a></dt> + <dd>부스트 코스를 통해 웹 개발을 심도 있게 배울 수 있음</dd> + <dt><a href="https://www.acmicpc.net/">Baekjoon Online Judge</a></dt> + <dd>다양한 코딩 문제를 풀어볼 수 있음</dd> + <dt><a href="https://learning.mozilla.org/activities">Teaching activities</a></dt> + <dd>모질라 재단이 운영하는 학습 플랫폼으로 기본적인 웹 활용 방법과 개인 정보 보호부터 JavaScript와 Minecraft 해킹까지 배울 수 있음</dd> + <dt><a href="https://www.w3schools.com/">w3schools</a> </dt> + <dd>세계에서 가장 큰 웹 개발자 사이트가 모토이며, 모질라와는 달리 설명하는 문장이 길지않고 짤막한 단문으로 이해하기 쉬우며 예제 중심으로 설명하고 있음. 또한 사이트 메뉴가 원하는 주제를 찾기 쉽게 구성 되어 있음</dd> +</dl> diff --git a/files/ko/learn/index/index.html b/files/ko/learn/index/index.html new file mode 100644 index 0000000000..ef35585b45 --- /dev/null +++ b/files/ko/learn/index/index.html @@ -0,0 +1,10 @@ +--- +title: Index +slug: Learn/Index +tags: + - Index + - Learn + - MDN Meta +translation_of: Learn/Index +--- +<p>{{Index("/ko/docs/Learn")}}</p> diff --git a/files/ko/learn/infrastructure/index.html b/files/ko/learn/infrastructure/index.html new file mode 100644 index 0000000000..b2fb5c62b7 --- /dev/null +++ b/files/ko/learn/infrastructure/index.html @@ -0,0 +1,18 @@ +--- +title: Infrastructure +slug: Learn/Infrastructure +translation_of: Learn/Common_questions +--- +<p><span style="line-height: 1.5;">이 능력은 인터넷 기술 스택에 대해 잘 이해할 수 있도록 해줍니다. 알아야 할 것들을 작고, 세부적 기술들로 나누었습니다:</span></p> + +<h2 id="기본_스킬" style="line-height: 30px; font-size: 2.14285714285714rem;">기본 스킬</h2> + +<p>웹에 익숙하지 않으시다면 여기서부터 시작하세요. 웹에 관련된 전문용어를 이해하기위해서 <a href="https://developer.mozilla.org/en-US/docs/Glossary">용어사전</a>을 참고하는 것을 추천합니다.</p> + +<h2 id="중급_스킬" style="line-height: 30px; font-size: 2.14285714285714rem;">중급 스킬</h2> + +<p>웹에 익숙해지셨다면, 여기에 더 자세한 것들이 있습니다:</p> + +<h2 id="고급_스킬" style="line-height: 30px; font-size: 2.14285714285714rem;">고급 스킬</h2> + +<p>경험있는 웹 저자라면, 특정 주제나 특별한 기술들에 흥미를 느끼실 것입니다.</p> diff --git a/files/ko/learn/javascript/asynchronous/async_await/index.html b/files/ko/learn/javascript/asynchronous/async_await/index.html new file mode 100644 index 0000000000..339a9dabdb --- /dev/null +++ b/files/ko/learn/javascript/asynchronous/async_await/index.html @@ -0,0 +1,383 @@ +--- +title: Making asynchronous programming easier with async and await +slug: Learn/JavaScript/Asynchronous/Async_await +translation_of: Learn/JavaScript/Asynchronous/Async_await +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Asynchronous/Promises", "Learn/JavaScript/Asynchronous/Choosing_the_right_approach", "Learn/JavaScript/Asynchronous")}}</div> + +<p class="summary">Javascript에 대한 최신 추가 사항은 ECMAScript 2017 JavaScript 에디션의 일부인 <a href="/en-US/docs/Web/JavaScript/Reference/Statements/async_function">async functions</a> 그리고 <code><a href="/en-US/docs/Web/JavaScript/Reference/Operators/await">await</a></code> 키워드 입니다.(<a href="/en-US/docs/Web/JavaScript/New_in_JavaScript/ECMAScript_Next_support_in_Mozilla">ECMAScript Next support in Mozilla</a>를 참조하세요). 이러한 기능들은 Promise기반 코드를 좀 더 쓰기 쉽고 읽기 쉽게 만들어줍니다. 이 기능을 사용하면 비동기 코드를 구식 동기 코드처럼 보여주기 때문에 충분히 배울 가치가 있습니다.이번 문서에서 위의 기능을 어떻게 사용하는지 배울 것 입니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Prerequisites:</th> + <td>Basic computer literacy, a reasonable understanding of JavaScript fundamentals, an understanding of async code in general and promises.</td> + </tr> + <tr> + <th scope="row">Objective:</th> + <td>To understand promises and how to use them.</td> + </tr> + </tbody> +</table> + +<h2 id="The_basics_of_asyncawait">The basics of async/await</h2> + +<p>async/await 코드는 두 가지 부분으로 나눠져있습니다.</p> + +<h3 id="The_async_keyword">The async keyword</h3> + +<p>먼저 비 동기 함수를 <a href="/en-US/docs/Web/JavaScript/Reference/Statements/async_function">async function</a>으로 만들기 위하여 function()앞에 <code>async</code> keyword를 추가합니다. async function()은 <code>await</code> 키워드가 비동기 코드를 호출할 수 있게 해주는 함수 입니다.</p> + +<p>브라우저의 JavaScript 콘솔에서 아래와 같이 입력해보세요. :</p> + +<pre class="brush: js notranslate">function hello() { return "Hello" }; +hello();</pre> + +<p>위의 함수는 "Hello"를 반환합니다. — 특별할게 없죠?</p> + +<p>그러면 함수 앞에 async 키워드를 추가하면 어떻게 될까요?? 아래처럼 작성해봅시다.:</p> + +<pre class="brush: js notranslate">async function hello() { return "Hello" }; +hello();</pre> + +<p>이제 코드가 Promise를 반환합니다. 이것이 async 기능의 특징 중 하나 입니다. — 이 키워드를 사용하면 반환받는 값은 Promise가 됩니다..</p> + +<p><a href="/en-US/docs/Web/JavaScript/Reference/Operators/async_function">async function expression</a>을 사용하여 아래와 같이 만들 수도 있습니다. :</p> + +<pre class="brush: js notranslate">let hello = async function() { return "Hello" }; +hello();</pre> + +<p>화살표 함수를 사용하면 아래처럼 쓸 수 있습니다. :</p> + +<pre class="brush: js notranslate">let hello = async () => { return "Hello" };</pre> + +<p>기본적으로 두 가지는 모두 같습니다.</p> + +<p>실제로는 fulfil Promise가 반환되기 때문에 반환된 값을 사용하기 위해선 <code>.then()</code> 블럭을 사용해야 합니다. :</p> + +<pre class="brush: js notranslate">hello().then((value) => console.log(value))</pre> + +<p>짧개 표현하면 아래와 같이 쓸 수 있습니다.</p> + +<pre class="brush: js notranslate">hello().then(console.log)</pre> + +<p>이전에 봤던 내용과 비슷하죠?.</p> + +<p>정리하면, <code>async</code> 를 함수와 같이 사용하면 결과를 직접 반환하는게 아니라 Promise를 반환하게 합니다. 또한 동기식 함수는 <code>await</code>사용을 위한 지원과 함께 실행되는 잠재적인 오버헤드를 피할 수 있습니다. 함수가 <code>async</code>라고 선언될 때 필요한 핸들링만 추가하면 JavaScript엔진이 우리가 만든 프로그램을 최적화 할 수 있습니다. 끝내주죠?</p> + +<h3 id="The_await_keyword">The await keyword</h3> + +<p>비동기 함수를 <a href="/en-US/docs/Web/JavaScript/Reference/Operators/await">await</a> 키워드와 함께 쓰면 그 장점이 확실히 보입니다. 이것은 어떠한 Promise기반 함수 앞에 놓을 수 있습니다. 그리고 우리의 코드의 Promise가 fulfil될 때 까지 잠시 중단하고, 결과를 반환합니다. 그리고 실행을 기다리는 다른 코드들을 중지시키지 않고 그대로 실행되게 합니다.</p> + +<p><code>await</code> 키워드는 웹 API를 포함하여 Promise를 반환하는 함수를 호출할 때 사용할 수 있습니다.</p> + +<p>여기 간단한 예가 있습니다. :</p> + +<pre class="brush: js notranslate">async function hello() { + return greeting = await Promise.resolve("Hello"); +}; + +hello().then(alert);</pre> + +<p>물론 위의 예시는 그다지 쓸모있진 않습니다. 다만 어떻게 구문을 작성해야 하는지는 잘 나타내줍니다. 이제 실제 사례를 살펴봅시다.</p> + +<h2 id="Rewriting_promise_code_with_asyncawait">Rewriting promise code with async/await</h2> + +<p>이전 문서에서 봤던 간단한 fetch() 예제를 살펴봅시다. :</p> + +<pre class="brush: js notranslate">fetch('coffee.jpg') +.then(response => response.blob()) +.then(myBlob => { + let objectURL = URL.createObjectURL(myBlob); + let image = document.createElement('img'); + image.src = objectURL; + document.body.appendChild(image); +}) +.catch(e => { + console.log('There has been a problem with your fetch operation: ' + e.message); +});</pre> + +<p>지금 시점에서 우리는 Promise가 어떻게 작동하는지 잘 이해하고 있습니다. 그렇다면 지금부터 이 예제를 async/await 를 사용하여 더 간단하게 만들어봅시다. :</p> + +<pre class="brush: js notranslate">async function myFetch() { + let response = await fetch('coffee.jpg'); + let myBlob = await response.blob(); + + let objectURL = URL.createObjectURL(myBlob); + let image = document.createElement('img'); + image.src = objectURL; + document.body.appendChild(image); +} + +myFetch() +.catch(e => { + console.log('There has been a problem with your fetch operation: ' + e.message); +});</pre> + +<p>바꾸고 나니 더 이해하기 쉬워졌습니다. — 더 이상의 <code>.then()</code> 블럭은 찾아 볼 수 없습니다.</p> + +<p><code>async</code> 키워드가 함수를 Promise로 바꾸었기, 이제 promise 와 await의 하이브리드 접근방식을 사용하기 위해 코드를 리팩토링 할 수 있으며, 두 번째 <code>.then()</code>블럭을 함수 내부의 블럭으로 가져와 더 유연하게 만들 수 있습니다.</p> + +<pre class="brush: js notranslate">async function myFetch() { + let response = await fetch('coffee.jpg'); + return await response.blob(); +} + +myFetch().then((blob) => { + let objectURL = URL.createObjectURL(blob); + let image = document.createElement('img'); + image.src = objectURL; + document.body.appendChild(image); +}).catch(e => console.log(e));</pre> + +<p>예제를 직접 만들어보거나, 여기서 결과를 확인할 수 있습니다. <a href="https://mdn.github.io/learning-area/javascript/asynchronous/async-await/simple-fetch-async-await.html">live example</a> (see also the <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/async-await/simple-fetch-async-await.html">source code</a>).</p> + +<h3 id="But_how_does_it_work">But how does it work?</h3> + +<p>함수 안에 코드를 작성했고, <code>function</code> 키워드 앞에 <code>async</code> 키워드를 썼다는 것을 알 수 있습니다. 꼭 이렇게 써야합니다!! 비동기 코드를 실행할 블럭을 정의하려면 비동기 함수를 생성해야 합니다. <code>await</code>는 <code>async function</code> 안에서만 쓸 수 있습니다.</p> + +<div class="blockIndicator note"> +<p><strong>Note:</strong> It's worth saying again, in a box with an eye-catching background color: <code>await</code> only works inside async functions.</p> +</div> + +<p><code>myFetch()</code> 함수 내에 코드가 이전의 Promise버전과 매우 유사하지만, 다른점이 있습니다. <code>.then()</code>블럭을 사용하여 작업을 이어가는 대신 메서드 호출 전에 <code>await</code> 키워드를 사용하여 반환된 결과를 변수에 할당합니다. <code>await</code> 키워드는 JavaScript 런타임이 이 라인에서 비동기 코드를 일시 중지하여 비동기 함수 호출이 결과를 반환할 때 까지 기다리게 합니다. 그러나 외부의 다른 동기 코드는 실행될 수 있도록 합니다. 작업이 완료되면 코드는 계속 이어져서 실행됩니다. 예를들면 아래와 같습니다. :</p> + +<pre class="brush: js notranslate">let response = await fetch('coffee.jpg');</pre> + +<p>fullfilled된 <code>fetch()</code> Promise에서 반환된 응답은 해당 응답이 사용할 수 있게 되면 <code>response</code> 변수에 할당됩니다. 그리고 parser는 해당 응답이 발생할 때 까지 이 라인에서 일시 중지됩니다. response가 사용 가능하게 되면, parser 는 다음 라인으로 이동하게 되고 그 라인에서 <code><a href="/en-US/docs/Web/API/Blob">Blob</a></code> 을 생성하게 됩니다. 이라인도 Promise기반 비동기 메서드를 호출하므로, 여기서도<code>await</code> 을 사용합니다. 비동기 작업 결과가 반환되면, <code>myFetch()</code> 함수가 그 결과를 반환합니다.</p> + +<p><code>myFetch()</code> 함수를 호출하면, Promise를 반환하므로, 따라서 화면에 Blob을 표시해주는 <code>.then()</code> 코드 블럭 체이닝 할 수 있습니다.</p> + +<p>여기까지 왔으면 이 방법이 멋있다고 생각해야합니다! 왜냐하면 <code>.then()</code> 블럭이 줄어들고 대부분이 동기 코드처럼 보이기 때문에 정말 직관적입니다.</p> + +<h3 id="Adding_error_handling">Adding error handling</h3> + +<p>그리고 오류 처리를 하려면 몇 가지 옵션이 있습니다.</p> + +<p>동기식 코드에서 쓰는 <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/try...catch">try...catch</a></code> 구문을 <code>async</code>/<code>await</code>구조에서 사용할 수 있습니다. 이 예제는 위에서 설명한 첫 번째 코드를 수정한 것 입니다. :</p> + +<pre class="brush: js notranslate">async function myFetch() { + try { + let response = await fetch('coffee.jpg'); + let myBlob = await response.blob(); + + let objectURL = URL.createObjectURL(myBlob); + let image = document.createElement('img'); + image.src = objectURL; + document.body.appendChild(image); + } catch(e) { + console.log(e); + } +} + +myFetch();</pre> + +<p><code>catch() {}</code> 블록은 <code>e</code> 라고 부르는 에러 오브젝트를 통과시킵니다. 이제 콘솔에 코드가 던져준 에러 메시지를 출력할 수 있습니다.</p> + +<p>아래 코드는 처음 예제를 리팩토링한 두 번째 버전의 코드 입니다. 이 하이브리드 접근법을 사용하는 코드에서 에러를 탐지하고 싶으면 <code>.catch()</code> 블럭을 <code>.then()</code> 호출의 마지막에 작성합니다. :</p> + +<pre class="brush: js notranslate">async function myFetch() { + let response = await fetch('coffee.jpg'); + return await response.blob(); +} + +myFetch().then((blob) => { + let objectURL = URL.createObjectURL(blob); + let image = document.createElement('img'); + image.src = objectURL; + document.body.appendChild(image); +}) +.catch((e) => + console.log(e) +);</pre> + +<p>이는 <code>.catch()</code> 블럭이 async 함수 호출과 Promise 체인 모두에서 발생하는 오류를 잡을 수 있기 때문입니다. 여기서 <code>try</code>/<code>catch</code> 블럭을 사용했더라도, <code>myFetch()</code> 에서 발생한 unhandled에러를 잡아낼 수 있습니다.</p> + +<p>위의 예제 모두를 GitHub에서 찾아볼 수 있습니다. :</p> + +<ul> + <li><a href="https://mdn.github.io/learning-area/javascript/asynchronous/async-await/simple-fetch-async-await-try-catch.html">simple-fetch-async-await-try-catch.html</a> (see <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/async-await/simple-fetch-async-await-try-catch.html">source code</a>)</li> + <li><a href="https://mdn.github.io/learning-area/javascript/asynchronous/async-await/simple-fetch-async-await-promise-catch.html">simple-fetch-async-await-promise-catch.html</a> (see <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/async-await/simple-fetch-async-await-promise-catch.html">source code</a>)</li> +</ul> + +<h2 id="Awaiting_a_Promise.all">Awaiting a Promise.all()</h2> + +<p>async/await는 <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">promises</a>의 상위에 만들어져 있기 때문에 Promise의 모든 기능을 사용할 수 있습니다. <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all">Promise.all()</a></code> 을 포함해서 말이죠 — 아래 보이는 코드처럼 <code>Promise.all()</code> 앞에 <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">async</span></font>키워드를 사용하여 동기식 코드처럼 작성할 수 있습니다. 이전 문서를 확인해봅시다. <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/promise-all.html">an example we saw in our previous article</a>. 새로운 버전과 비교하기 위해 탭을 분리 해보세요.</p> + +<p>Aasync/await 스타일로 변경한 코드는 아래와 같습니다. (see <a href="https://mdn.github.io/learning-area/javascript/asynchronous/async-await/promise-all-async-await.html">live demo</a> and <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/async-await/promise-all-async-await.html">source code</a>) :</p> + +<pre class="brush: js notranslate">async function fetchAndDecode(url, type) { + let response = await fetch(url); + + let content; + + if(type === 'blob') { + content = await response.blob(); + } else if(type === 'text') { + content = await response.text(); + } + + return content; +} + +async function displayContent() { + let coffee = fetchAndDecode('coffee.jpg', 'blob'); + let tea = fetchAndDecode('tea.jpg', 'blob'); + let description = fetchAndDecode('description.txt', 'text'); + + let values = await Promise.all([coffee, tea, description]); + + let objectURL1 = URL.createObjectURL(values[0]); + let objectURL2 = URL.createObjectURL(values[1]); + let descText = values[2]; + + let image1 = document.createElement('img'); + let image2 = document.createElement('img'); + image1.src = objectURL1; + image2.src = objectURL2; + document.body.appendChild(image1); + document.body.appendChild(image2); + + let para = document.createElement('p'); + para.textContent = descText; + document.body.appendChild(para); +} + +displayContent() +.catch((e) => + console.log(e) +);</pre> + +<p>몇 가지 사항을 조금 수정했을 뿐인데 <code>fetchAndDecode()</code>함수를 쉽게 비동기 함수로 변환했습니다. <code>Promise.all()</code> 라인을 살펴보세요:</p> + +<pre class="brush: js notranslate">let values = await Promise.all([coffee, tea, description]);</pre> + +<p>여기에 <code>await</code> 을 사용하여 세 가지 Promise의 결과가 반환되었을 때 <code>values</code> 배열에 담을 수 있습니다. 그리고 마치 동기화 코드처럼 보이죠. 우리가 작업한건 <code>displayContent()</code>에 <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">async</span></font>키워드를 추가하고, 모든 코드를<code>.then()</code> 블럭 바깥으로 빼냈습니다. 또한 아주 적은양의 코드 수정도 했죠. 이렇게 하니 더 단순하고, 유용하고 읽기 쉬운 프로그램이 되었습니다.</p> + +<p>마지막으로 에러를 다루기 위해 <code>.catch()</code> 블럭을 <code>displayContent()</code> 함수를 호출하는 곳에 추가했습니다. 이렇게 하면 두 함수에서 발생하는 에러를 처리할 수 있습니다.</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: It is also possible to use a sync <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/try...catch#The_finally_clause">finally</a></code> block within an async function, in place of a <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/finally">.finally()</a></code> async block, to show a final report on how the operation went — you can see this in action in our <a href="https://mdn.github.io/learning-area/javascript/asynchronous/async-await/promise-finally-async-await.html">live example</a> (see also the <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/async-await/promise-finally-async-await.html">source code</a>).</p> +</div> + +<h2 id="The_downsides_of_asyncawait">The downsides of async/await</h2> + +<p>앞서 봤듯이 async/await 은매우 유용하지만 고려해야 할 몇 가지 단점이 있습니다.</p> + +<p>Async/await 는 우리의 코드를 마치 동기식 코드처럼 보이게 합니다. 그리고 어떤 면에서는 정말로 동기적으로 행동합니다. 함수 블럭에 여러 개의 <code>await</code> 키워드를 사용하면 Promise가 fulfilled되기 전 까지 다음 <code>await</code> 을 차단합니다. 그 동안 다른 태스크는 계속 실행이 되지만 정의한 함수 내에서는 동기적으로 작동할 것 입니다.</p> + +<p>이 말은 우리가 작성한 코드가 바로 이어지는 수 많은 Promise에 의해 느려질 수 있다는 것을 의미합니다. 각 <code>await</code> 는 이전의 작업이 끝날 때 까지 기다립니다(Promise 체이닝과 혼동하지 마세요). 그런데 우리가 원하는건 기다리는게 아니고 일제히 실행되는 것 입니다.</p> + +<p>이 문제를 완화할 수 있는 패턴이 있습니다. — 모든 <code>Promise</code> 오브젝트를 변수에 저장하여 미리 실행되게 하고 변수가 사용 가능할 때 꺼내서 쓰는 것 입니다. 어떻게 작동하는지 한번 살펴봅시다.</p> + +<p>두 가지 예시를 보여주겠습니다. — 느린 비동기 작업 <a href="https://mdn.github.io/learning-area/javascript/asynchronous/async-await/slow-async-await.html">slow-async-await.html</a> (see <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/async-await/slow-async-await.html">source code</a>) 그리고 빠른 비동기 작업 <a href="https://mdn.github.io/learning-area/javascript/asynchronous/async-await/fast-async-await.html">fast-async-await.html</a> (see <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/async-await/fast-async-await.html">source code</a>)입니다. 두 예제에서 마치 비동기 작업인 것 처럼 보이기 위해 <code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout">setTimeout()</a></code> 을 사용했습니다. :</p> + +<pre class="brush: js notranslate">function timeoutPromise(interval) { + return new Promise((resolve, reject) => { + setTimeout(function(){ + resolve("done"); + }, interval); + }); +};</pre> + +<p>그리고 세 가지 <code>timeoutPromise()</code> 함수를 호출하는 <code>timeTest()</code>함수를 만들었습니다.</p> + +<pre class="brush: js notranslate">async function timeTest() { + ... +}</pre> + +<p>그리고 두 개 예제 모두 시작 시간을 기록하고, <code>timeTest()</code> Promise가 fulfilled된 시간을 저장하여 두 시간의 차를 계산해 작업이 얼마나 걸렸는지 사용자에게 보여줍니다. :</p> + +<pre class="brush: js notranslate">let startTime = Date.now(); +timeTest().then(() => { + let finishTime = Date.now(); + let timeTaken = finishTime - startTime; + alert("Time taken in milliseconds: " + timeTaken); +})</pre> + +<p><code>timeTest()</code> 함수만 두 예제에서 차이가 있습니다.</p> + +<p><code>slow-async-await.html</code> 예제이서, <code>timeTest()</code> 함수는 아래와 같이 생겼습니다. :</p> + +<pre class="brush: js notranslate">async function timeTest() { + await timeoutPromise(3000); + await timeoutPromise(3000); + await timeoutPromise(3000); +}</pre> + +<p>아주 간단하게 <code>timeoutPromise()</code> 함수를 직접 호출했습니다. 각 작업은 3초씩 걸립니다. 그리고 <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">await</span></font> 키워드를 사용했기 때문에 이전 await 작업이 끝나야 다음으로 진행됩니다. — 첫 번째 예제를 실행하면, alert 박스에서 약 9초(9000밀리초)가 걸렸음을 확인할 수 있습니다.</p> + +<p>다음으로 <code>fast-async-await.html</code> 예제이서, <code>timeTest()</code> 은 아래와 같이 생겼습니다. :</p> + +<pre class="brush: js notranslate">async function timeTest() { + const timeoutPromise1 = timeoutPromise(3000); + const timeoutPromise2 = timeoutPromise(3000); + const timeoutPromise3 = timeoutPromise(3000); + + await timeoutPromise1; + await timeoutPromise2; + await timeoutPromise3; +}</pre> + +<p>여기선 세 가지 <code>Promise</code> 오브젝트를 변수에 저장하여 동시에 작업을 시작하도록 했습니다.</p> + +<p>그리고 그 변수에 await을 사용하여 결과를 호출합니다. — 작업이 거의 동시에 시작됐기 때문에, Promise도 거의 동시에 fulfilled될 것 입니다. 두 번째 예제를 실행하면 거의 3초(3000밀리초) 만에 작업이 끝났음을 확인할 수 있습니다.</p> + +<p>코드를 주의깊게 테스트 하고, 성능이 떨어지기 시작하면 위의 상황을 의심해봐야 합니다.</p> + +<p>다른 아주 사소한 단점은 비동기로 실행될 Promise가 있다면 async함수 안에 항상 await을 써야한다는 것 입니다.</p> + +<h2 id="Asyncawait_class_methods">Async/await class methods</h2> + +<p>마지막으로 보여줄 내용은 <code>async</code> 키워드를 class/object의 메서드에 사용하여 Promise를 반환하게 만들 수 있다는 것 입니다. 그리고 <code>await</code> 를 그 안에 넣을 수도 있습니다. 다음 문서를 살펴보세요 > <a href="/en-US/docs/Learn/JavaScript/Objects/Inheritance#ECMAScript_2015_Classes">ES class code we saw in our object-oriented JavaScript article</a>, 그리고 보이는 코드를<code>async</code> 메서드로 수정한 아래의 내용과 비교 해보세요 :</p> + +<pre class="brush: js notranslate">class Person { + constructor(first, last, age, gender, interests) { + this.name = { + first, + last + }; + this.age = age; + this.gender = gender; + this.interests = interests; + } + + async greeting() { + return await Promise.resolve(`Hi! I'm ${this.name.first}`); + }; + + farewell() { + console.log(`${this.name.first} has left the building. Bye for now!`); + }; +} + +let han = new Person('Han', 'Solo', 25, 'male', ['Smuggling']);</pre> + +<p>이제 클래스의 첫 번째 메서드를 아래와 같이 사용할 수 있습니다. :</p> + +<pre class="brush: js notranslate">han.greeting().then(console.log);</pre> + +<h2 id="Browser_support">Browser support</h2> + +<p>One consideration when deciding whether to use async/await is support for older browsers. They are available in modern versions of most browsers, the same as promises; the main support problems come with Internet Explorer and Opera Mini.</p> + +<p>If you want to use async/await but are concerned about older browser support, you could consider using the <a href="https://babeljs.io/">BabelJS</a> library — this allows you to write your applications using the latest JavaScript and let Babel figure out what changes if any are needed for your user’s browsers. On encountering a browser that does not support async/await, Babel's polyfill can automatically provide fallbacks that work in older browsers.</p> + +<h2 id="Conclusion">Conclusion</h2> + +<p>And there you have it — async/await provide a nice, simplified way to write async code that is simpler to read and maintain. Even with browser support being more limited than other async code mechanisms at the time of writing, it is well worth learning and considering for use, both for now and in the future.</p> + +<p>{{PreviousMenuNext("Learn/JavaScript/Asynchronous/Promises", "Learn/JavaScript/Asynchronous/Choosing_the_right_approach", "Learn/JavaScript/Asynchronous")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Concepts">General asynchronous programming concepts</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Introducing">Introducing asynchronous JavaScript</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Timeouts_and_intervals">Cooperative asynchronous JavaScript: Timeouts and intervals</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Promises">Graceful asynchronous programming with Promises</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Async_await">Making asynchronous programming easier with async and await</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Choosing_the_right_approach">Choosing the right approach</a></li> +</ul> diff --git a/files/ko/learn/javascript/asynchronous/concepts/index.html b/files/ko/learn/javascript/asynchronous/concepts/index.html new file mode 100644 index 0000000000..443487fefb --- /dev/null +++ b/files/ko/learn/javascript/asynchronous/concepts/index.html @@ -0,0 +1,159 @@ +--- +title: 일반적인 비동기 프로그래밍 개념 +slug: Learn/JavaScript/Asynchronous/Concepts +tags: + - 비동기 + - 비동기 프로그래밍 + - 자바스크립트 +translation_of: Learn/JavaScript/Asynchronous/Concepts +--- +<div>{{LearnSidebar}}{{NextMenu("Learn/JavaScript/Asynchronous/Introducing", "Learn/JavaScript/Asynchronous")}}</div> + +<p>이 문서에서는 비동기적 프로그래밍과 관련된 몇개의 개념들을 살펴볼 것입니다. 그리고 이것들이 웹브라우저와 자바스크립트에서 어떻게 보이는지도 살펴볼 것입니다. 이 모듈의 다른 문서들을 공부하기 전에, 이 문서에 나와있는 개념들을 먼저 학습하십시오.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">선행 조건:</th> + <td>기초적인 컴퓨터 언어 능력, Javascript에 대한 기초적인 이해가 필요합니다. </td> + </tr> + <tr> + <th scope="row">학습 목적: </th> + <td>비동기적 프로그래밍이 작동하는 기초적인 원리에 대해 이해하는 것입니다. 그리고 이 개념이 어떻게 웹브라우저와 자바스크립트에서 압도적인 지위를 차지하기 되었는지 알아봅니다. </td> + </tr> + </tbody> +</table> + +<h2 id="비동기적Asynchronous_이란">'비동기적'(Asynchronous) 이란?</h2> + +<p>일반적으로, 프로그램의 코드는 순차적으로 진행됩니다. 한번에 한가지 사건만 발생하면서 말입니다. 만약 어떤 함수의 결과가 다른 함수에 영향을 받는다면, 그 함수는 다른 함수가 끝나고 값을 산출할 때까지 기다려야 합니다. 그리고 그 과정이 끝날 때 까지, 유저의 입장에서 보자면, 전체 프로그램이 모두 멈춘 것처럼 보입니다. </p> + +<p>예를들면, 맥 유저라면 종종 회전하는 무지개색 커서(비치볼)를 본 적이 있을 것입니다. 이 커서는 오퍼레이팅 시스템이 이렇게 말하고 있는 것입니다. "당신이 지금 사용하고 있는 시스템은 지금 멈춰서서 뭔가가 끝나기를 기다려야만 합니다. 그리고 이 과정은 당신이 지금 무슨 일이 일어나고있는지 궁금해 할 만큼 오래 걸리고 있습니다."</p> + +<p><img alt="Multi-colored macOS beachball busy spinner" src="https://mdn.mozillademos.org/files/16577/beachball.jpg" style="display: block; float: left; height: 256px; margin: 0px 30px 0px 0px; width: 250px;"></p> + +<p>이것은 당황스러운 경험이며, 특히 요즘과 같이 컴퓨터가 여러개 프로세서를 돌리는 시대에는 컴퓨터 성능을 효율적으로 쓰지 못하는 처사입니다. 당신이 다른 코어 프로세서에 다른 작업들을 움직이게 하고 작업이 완료되면 알려줄 수 있을 때, 무언가를 기다리는 것은 의미가 없습니다 .그 동안 다른 작업을 수행할 수 있고, 이것이 비동기 프로그래밍의 기본입니다. 이러한 작업을 비동기적으로 실행할 수 있는 API를 제공하는 것은 당신이 사용하고 있는 프로그래밍 환경(웹 개발의 경우 웹브라우저) 에 달려 있습니다.</p> + +<h2 id="Blocking_code">Blocking code</h2> + +<p>비동기 기법은 특히 웹 프로그래밍에 매우 유용합니다. 웹 앱이 브라우저에서 특정 코드를 실행하느라 브라우저에게 제어권을 돌려주지 않으면 브라우저는 마치 정지된 것처럼 보일 수 있습니다. 이러한 현상을 <strong>blocking </strong>이라고 부릅니다. 자세히 정의하자면, 사용자의 입력을 처리하느라 웹 앱이 프로세서에 대한 제어권을 브라우저에게 반환하지 않는 현상 입니다..</p> + +<p>Blocking의 몇 가지 예를 살펴보겠습니다.</p> + +<p>여기 <a href="https://github.com/mdn/learning-area/tree/master/javascript/asynchronous/introducing">simple-sync.html</a> 예시가 있습니다. (<a href="https://mdn.github.io/learning-area/javascript/asynchronous/introducing/simple-sync.html">see it running live</a>), 하나의 버튼에 클릭 이벤트리스너를 지정하여 시간이 오래 걸리는 처리를 하도록하였습니다. (날짜를 천만번 계산하고 마지막에 콘솔에 날짜를 출력합니다.) 그리고 처리가 끝나면 페이지에 간단한 문장을 한 줄 출력합니다. :</p> + +<pre class="brush: js notranslate">const btn = document.querySelector('button'); +btn.addEventListener('click', () => { + let myDate; + for(let i = 0; i < 10000000; i++) { + let date = new Date(); + myDate = date + } + + console.log(myDate); + + let pElem = document.createElement('p'); + pElem.textContent = 'This is a newly-added paragraph.'; + document.body.appendChild(pElem); +});</pre> + +<p>이 예제를 실행할 때 JavaScript 콘솔을 열고 버튼을 클릭하면, 콘솔에 메시지가 출력되기 전 까지 페이지에 문장이 나타나지 않는다는 것을 알 수 있습니다. 코드는 위에서 아래로 순차적으로 실행되며, 아래쪽 코드는 위쪽 코드의 처리가 끝날 때 까지 실행되지 않습니다.</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: 앞의 예제는 매우 비현실적입니다. 실제 웹 앱에서 날짜를 천만번 계산할 일은 없습니다. 실제로 보여주기 위해 극단적인 예시를 들었을 뿐입니다..</p> +</div> + +<p>두 번째 예제를 살펴보겠습니다. <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/introducing/simple-sync-ui-blocking.html">simple-sync-ui-blocking.html</a> (<a href="https://mdn.github.io/learning-area/javascript/asynchronous/introducing/simple-sync-ui-blocking.html">see it live</a>), 페이지에 UI가 모두 표시되기 전 까지 사용자의 입력을 막는 좀 더 현실적인 예시입니다. 이번 예시에는 두 가지 버튼을 사용합니다. :</p> + +<ul> + <li>"Fill canvas" 버튼을 클릭하면 {{htmlelement("canvas")}} 태그에 100만개의 파란색 원을 채웁니다. (실행하면 원이 너무 많아서 원이 아니라 배경이 그냥 파란색으로 채워집니다.)</li> + <li>"Click me for alert" 버튼은 사용자에게 메시지를 출력합니다.</li> +</ul> + +<pre class="brush: js notranslate">function expensiveOperation() { + for(let i = 0; i < 1000000; i++) { + ctx.fillStyle = 'rgba(0,0,255, 0.2)'; + ctx.beginPath(); + ctx.arc(random(0, canvas.width), random(0, canvas.height), 10, degToRad(0), degToRad(360), false); + ctx.fill() + } +} + +fillBtn.addEventListener('click', expensiveOperation); + +alertBtn.addEventListener('click', () => + alert('You clicked me!') +);</pre> + +<p>첫 번째 버튼을 클릭한 후 두 번째 버튼을 바로 클릭하면 경고 박스가 나타나지 않는 것을 확인할 수 있습니다. 첫 번째 버튼은 이벤트가 끝나기 전 까지 다음 작동을 막아버립니다.</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: OK, in our case, it is ugly and we are faking the blocking effect, but this is a common problem that developers of real apps fight to mitigate all the time.</p> +</div> + +<p>왜 이런 현상이 발생할까요? 답은 자바스크립트는 기본적으로 <strong>single threaded</strong>이기 때문입니다. 이 시점에서 <strong>threads</strong>의 개념을 소개할 필요가 있겠군요</p> + +<h2 id="Threads">Threads</h2> + +<p><strong>Thread</strong> 는 기본적으로 프로그램이 작업을 완료하는데 사용할 수 있는 단일 프로세스 입니다. 각 스레드는 한 번에 하나의 작업만 수행할 수 있습니다. :</p> + +<pre class="notranslate">Task A --> Task B --> Task C</pre> + +<p>위의 예시처럼 각 작업은 순차적으로 실행되며, 다음 작업을 시작하려면 앞의 작업이 완료되어야 합니다.</p> + +<p>앞서 말했듯이, 많은 컴퓨터들이 현재 여러 개의 CPU코어를 가지고 있기 때문에, 한 번에 여러가지 일을 수행할 수 있습니다. Multiple thread를 지원하는 프로그래밍 언어는 멀티코어 컴퓨터의 CPU를 사용하여 여러 작업을 동시에 처리할 수 있습니다. :</p> + +<pre class="notranslate">Thread 1: Task A --> Task B +Thread 2: Task C --> Task D</pre> + +<h3 id="JavaScript_is_single_threaded">JavaScript is single threaded</h3> + +<p>자바스크립트는 전통적으로 싱글 thread입니다. 컴퓨터가 여러 개의 CPU를 가지고 있어도 <strong>main thread</strong>라 불리는 단일 thread에서만 작업을 실행할 수 있습니다. 위의 예시는 아래처럼 실행됩니다. :</p> + +<pre class="notranslate">Main thread: Render circles to canvas --> Display alert()</pre> + +<p>JavaScript는 이러한 문제를 해결하기 위해 몇 가지 툴을 도입했습니다. <a href="https://wiki.developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API">Web workers</a>는 여러 개의 JavaScript 청크를 동시에 실행할 수 있도록 worker라고 불리는 별도의 스레드로 보낼 수 있습니다. 따라서 시간이 오래 걸리는 처리는 woker를 사용해 처리하면 blocking 발생을 막을 수 있습니다..</p> + +<pre class="notranslate"> Main thread: Task A --> Task C +Worker thread: Expensive task B</pre> + +<p>위의 내용을 잘 기억하시고 다음 예제를 살펴보세요. <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/introducing/simple-sync-worker.html">simple-sync-worker.html</a> (<a href="https://mdn.github.io/learning-area/javascript/asynchronous/introducing/simple-sync-worker.html">see it running live</a>), JavaScript 콘솔을 함께 열어주세요. 이전 예시는 날짜를 천만 번 계산하고 페이지에 문장을 출력했지만, 이번엔 천만번 계산 전 문장을 페이지에 출력해줍니다. 더이상 첫 번째 작업이 두 번째 작업을 차단하지 않습니다.</p> + +<h2 id="Asynchronous_code">Asynchronous code</h2> + +<p>Web worker는 꽤 유용하지만 이들도 한계가 있습니다. 주요한 내용은 Web worker는 {{Glossary("DOM")}} 에 접근할 수 없습니다. — UI를 업데이트하도록 worker에게 어떠한 지시도 직접 할 수 없습니다. 두 번째 예시에서 worker는 100만개의 파란색 원을 만들 수 없습니다. 단순히 숫자만 계산합니다.</p> + +<p>두 번째 문제는 worker에서 실행되는 코드는 차단되지 않지만 동기적으로 실행된다는 것 입니다. 이러한 문제는 함수를 사용할 때 발생합니다. 어떤 함수가 일의 처리를 위해 이전의 여러 프로세스의 결과를 return 받아야 할 경우 입니다. 동기적으로 실행되면 함수 실행에 필요한 매개변수를 받아올 수 없는 경우가 생기므로 함수는 사용자가 원하는 기능을 제대로 실행할 수 없습니다.</p> + +<pre class="notranslate">Main thread: Task A --> Task B</pre> + +<p>이 예시에서 Task A는 서버로부터 이미지를 가져오고 Task B는 그 이미지에 필터를 적용하는 것과 같은 작업을 수행한다고 가정합니다. Task A를 실행하고 결과를 반환할 시간도 없이 Task B를 실행해버리면 에러가 발생할 것 입니다. 왜냐햐면 Task A에서 이미지를 완전히 가져온 상태가 아니기 때문이죠.</p> + +<pre class="notranslate"> Main thread: Task A --> Task B --> |Task D| +Worker thread: Task C -----------> | |</pre> + +<p>이번 예시에선 Task D가 Task B와 Task C의 결과를 모두 사용한다고 가정합니다. Task B와 Task C가 동시에 아주 빠르게 결과를 반환하면 매우 이상적이겠지만, 현실은 그렇지 않습니다. Task D가 사용될 때 Task B, Task C 둘 중 어느 값이라도 입력이 되지 않을경우 에러가 발생합니다.</p> + +<p>이러한 문제를 해결하기 위해 브라우저를 통해 특정 작업을 비동기적으로 실행할 수 있습니다. 바로 <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promises</a> 를 사용하는것 입니다. 아래 예시처럼 Task A가 서버에서 이미지를 가져오는 동안 Task B를 기다리게 할 수 있습니다. :</p> + +<pre class="notranslate">Main thread: Task A Task B + Promise: |__async operation__|</pre> + +<p>위의 작업은 다른 곳에서 처리가 되므로, 비동기 작업이 진행되는 동안 main thread가 차단되지 않습니다.</p> + +<p>이번 문서에서 다룬 내용은 매우 중요한 내용입니다. 다음 문서에선 비동기 코드를 어떻게 쓸 수 있는지 살펴볼 계획이므로 끝까지 읽어주시면 좋겠습니다.</p> + +<h2 id="결론">결론</h2> + +<p>현대의 소프트웨어 설계는 프로그램이 한 번에 두 가지 이상의 일을 할 수 있도록 비동기 프로그래밍을 중심으로 돌아가고 있습니다. 보다 새롭고 강력한 API를 이용하면서, 비동기로 작업해야만 하는 사례가 많아질 것입니다. 예전에는 비동기 코드를 쓰기가 힘들었습니다. 여전히 아직 어렵지만, 훨씬 쉬워졌습니다. 이 모듈의 나머지 부분에서는 비동기 코드가 왜 중요한지, 위에서 설명한 일부 문제들을 방지하는 코드 설계 방법에 대해 자세히 알아봅시다.</p> + +<h2 id="이번_module_에서는..">이번 module 에서는..</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Concepts">일반적인 비동기 프로그래밍 개념</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Introducing">비동기 자바스크립트 소개</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Timeouts_and_intervals">협동하는 비동기 자바스크립트: Timeouts and intervals</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Promises">Promises와 함께하는 우아한 비동기 프로그래밍</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Async_await">비동기 프로그래밍을 쉽게 만드는 방법: async and await</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Choosing_the_right_approach">올바른 접근 방식 선택하기</a></li> +</ul> diff --git a/files/ko/learn/javascript/asynchronous/index.html b/files/ko/learn/javascript/asynchronous/index.html new file mode 100644 index 0000000000..bcf2abdd45 --- /dev/null +++ b/files/ko/learn/javascript/asynchronous/index.html @@ -0,0 +1,59 @@ +--- +title: Asynchronous JavaScript +slug: Learn/JavaScript/Asynchronous +tags: + - Beginner + - CodingScripting + - Guide + - JavaScript + - Landing + - NeedsTranslation + - Promises + - TopicStub + - async + - asynchronous + - await + - callbacks + - requestAnimationFrame + - setInterval + - setTimeout +translation_of: Learn/JavaScript/Asynchronous +--- +<div>{{LearnSidebar}}</div> + +<p class="summary"><span class="seoSummary">In this module we take a look at {{Glossary("asynchronous")}} {{Glossary("JavaScript")}}, why it is important, and how it can be used to effectively handle potential blocking operations such as fetching resources from a server.</span></p> + +<h2 id="Prerequisites">Prerequisites</h2> + +<p>Asynchronous JavaScript is a fairly advanced topic, and you are advised to work through <a href="/en-US/docs/Learn/JavaScript/First_steps">JavaScript first steps</a> and <a href="/en-US/docs/Learn/JavaScript/Building_blocks">JavaScript building blocks</a> modules before attempting this.</p> + +<p>If you are not familiar with the concept of asynchronous programming, you should definitely start with the <a href="/en-US/docs/Learn/JavaScript/Asynchronous/Concepts">General asynchronous programming concepts</a> article in this module. If you are, then you can probably skip to the <a href="/en-US/docs/Learn/JavaScript/Asynchronous/Introducing">Introducing asynchronous JavaScript</a> module.</p> + +<div class="note"> +<p><strong>Note</strong>: If you are working on a computer/tablet/other device where you don't have the ability to create your own files, you can try out (most of) the code examples in an online coding program such as <a href="http://jsbin.com/">JSBin</a> or <a href="https://thimble.mozilla.org/">Thimble</a>.</p> +</div> + +<h2 id="Guides">Guides</h2> + +<dl> + <dt><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Concepts">General asynchronous programming concepts</a></dt> + <dd> + <p>In this article we'll run through a number of important concepts relating to asynchronous programming, and how this looks in web browsers and JavaScript. You should understand these concepts before working through the other articles in the module.</p> + </dd> + <dt><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Introducing">Introducing asynchronous JavaScript</a></dt> + <dd>In this article we briefly recap the problems associated with sychronous JavaScript, and take a first look at some of the different asynchronous JavaScript techniques you'll encounter, showing how they can help us solve such problems.</dd> + <dt><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Loops_and_intervals">Cooperative asynchronous JavaScript: Timeouts and intervals</a></dt> + <dd>Here we look at the traditional methods JavaScript has available for running code asychronously after a set time period has elapsed, or at a regular interval (e.g. a set number of times per second), talk about what they are useful for, and look at their inherent issues.</dd> + <dt><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Promises">Handling async operations gracefully with Promises</a></dt> + <dd>Promises are a comparatively new feature of the JavaScript language that allow you to defer further actions until after the previous action has completed, or respond to its failure. This is really useful for setting up a sequence of operations to work correctly. This article shows you how promises work, where you'll see them in use in WebAPIs, and how to write your own.</dd> + <dt><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Async_await">Making asynchronous programming easier with async and await</a></dt> + <dd>Promises can be somewhat complex to set up and understand, and so modern browsers have implemented <code>async</code> functions and the <code>await</code> operator — the former allows standard functions to implicitly behave asynchronously with promises, whereas the latter can be used inside <code>async</code> functions to wait for promises before the function continues, making chaining of promises easier. This article explains <code>async</code>/<code>await</code>.</dd> + <dt><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Choosing_the_right_approach">Choosing the right approach</a></dt> + <dd>To finish this module off, we'll consider the different coding techniques and features we've discussed throughout, looking at which ones you should use when, with recommendations and reminders of common pitfalls where appropriate.</dd> +</dl> + +<h2 id="See_also">See also</h2> + +<ul> + <li><a href="https://eloquentjavascript.net/11_async.html">Asynchronous Programming</a> from the fantastic <a href="https://eloquentjavascript.net/">Eloquent JavaScript</a> online book by Marijn Haverbeke.</li> +</ul> diff --git a/files/ko/learn/javascript/asynchronous/introducing/index.html b/files/ko/learn/javascript/asynchronous/introducing/index.html new file mode 100644 index 0000000000..a63eb66158 --- /dev/null +++ b/files/ko/learn/javascript/asynchronous/introducing/index.html @@ -0,0 +1,281 @@ +--- +title: Introducing asynchronous JavaScript +slug: Learn/JavaScript/Asynchronous/Introducing +translation_of: Learn/JavaScript/Asynchronous/Introducing +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Asynchronous/Concepts", "Learn/JavaScript/Asynchronous/Timeouts_and_intervals", "Learn/JavaScript/Asynchronous")}}</div> + +<p class="summary">이 문서에선 JavaScript의 동기식 처리와 관련된 문제를 간략하게 요약하고, 앞으로 접하게 될 다른 비동기 기술들을 살펴보며, 어떻게 우리에게 도움이 될 수 있는지 살펴봅니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">준비:</th> + <td>Basic computer literacy, a reasonable understanding of JavaScript fundamentals.</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td> + <p>비동기 자바스크립트에 대해 더 알기 위해, 동기 스크립트와 어떤 부분이 다른지 그리고 사용 사례를 알 수 있다.</p> + </td> + </tr> + </tbody> +</table> + +<h2 id="Synchronous_JavaScript">Synchronous JavaScript</h2> + +<p><strong>{{Glossary("asynchronous")}}</strong> JavaScript가 무엇인지 이해하려면, 우리는 <strong>{{Glossary("synchronous")}}</strong> JavaScript가 무엇인지 알아야 합니다. 이 문서에선 이전 문서에서 본 정보의 일부를 요약하겠습니다.</p> + +<p>이전의 학습 모듈에서 살펴본 많은 기능들은 동기식 입니다. — 약간의 코드를 실행하면, 브라우저가 할 수 있는 한 빠르게 결과를 보여줍니다. 다음 예제를 살펴볼까요 (<a href="https://mdn.github.io/learning-area/javascript/asynchronous/introducing/basic-function.html">see it live here</a>, and <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/introducing/basic-function.html">see the source</a>):</p> + +<pre class="brush: js notranslate">const btn = document.querySelector('button'); +btn.addEventListener('click', () => { + alert('You clicked me!'); + + let pElem = document.createElement('p'); + pElem.textContent = 'This is a newly-added paragraph.'; + document.body.appendChild(pElem); +}); +</pre> + +<p>이 블럭에서 코드는 위에서 아래로 차례대로 실행됩니다. :</p> + +<ol> + <li>DOM에 미리 정의된 {{htmlelement("button")}} element 를 참조합니다.</li> + <li><code><a href="/en-US/docs/Web/API/Element/click_event">click</a></code> 이벤트 리스너를 만들어 버튼이 클릭됐을 때 아래 기능을 차례로 실행합니다. : + <ol> + <li><code><a href="/en-US/docs/Web/API/Window/alert">alert()</a></code> 메시지가 나타납니다.</li> + <li>메시지가 사라지면 {{htmlelement("p")}} element를 만듭니다.</li> + <li>그리고 text content를 만듭니다.</li> + <li>마지막으로 docuent body에 문장을 추가합니다.</li> + </ol> + </li> +</ol> + +<p>각 작업이 처리되는 동안 렌더링은 일시 중지됩니다. <a href="/en-US/docs/Learn/JavaScript/Asynchronous/Introducing">앞에서 말한 문서와 같이</a>, <a href="/en-US/docs/Learn/JavaScript/Asynchronous/Concepts#JavaScript_is_single_threaded">JavaScript 는 single threaded</a>이기 때문입니다. 한 번에 한 작업만, 하나의 main thread에서 처리될 수 있습니다. 그리고 다른 작업은 앞선 작업이 끝나야 수행됩니다.</p> + +<p>따라서 앞의 예제는 사용자가 OK 버튼을 누를 때까지 문장이 나타나지 않습니다. :</p> + +<div class="hidden"> +<pre class="brush: html notranslate"><<span class="pl-ent">button</span>>Click me</<span class="pl-ent">button</span>></pre> +</div> + +<p>{{EmbedLiveSample('Synchronous_JavaScript', '100%', '70px')}}</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: 기억해두세요. <code><a href="/en-US/docs/Web/API/Window/alert">alert()</a></code> 는 동기 블럭을 설명하는데 아주 유용하지만, 실제 어플리케이션에서 사용하기엔 아주 끔찍합니다.</p> +</div> + +<h2 id="Asynchronous_JavaScript">Asynchronous JavaScript</h2> + +<p>앞서 설명된 이유들 (e.g. related to blocking) 때문에 많은 웹 API기능은 현재 비동기 코드를 사용하여 실행되고 있습니다. 특히 외부 디바이스에서 어떤 종류의 리소스에 액세스 하거나 가져오는 기능들에 많이 사용합니다. 예를 들어 네트워크에서 파일을 가져오거나, 데이터베이스에 접속해 특정 데이터를 가져오는 일, 웹 캠에서 비디오 스트림에 엑세스 하거나, 디스플레이를 VR 헤드셋으로 브로드캐스팅 하는것 입니다.</p> + +<p>동기적 코드를 사용하여 작업을 처리하는데 왜 이렇게 어려울까요? 다음 예제를 살펴보겠습니다. 서버에서 이미지를 가져오면 네트워크 환경, 다운로드 속도 등의 영향을 받아 이미지를 즉시 확인할 수 없습니다. 이 말은 아래 코드가 (pseudocode) 실행되지 않는다는 의미 입니다. :</p> + +<pre class="brush: js notranslate">let response = fetch('myImage.png'); +let blob = response.blob(); +// display your image blob in the UI somehow</pre> + +<p>왜냐하면 앞서 설명했듯이 이미지를 다운로드 받는데 얼마나 걸릴지 모르기 때문입니다. 그래서 두 번째 줄을 실행하면 에러가 발생할 것 입니다. (이미지의 크키가 아주 작다면 에러가 발생하지 않을 수도 있습니다. 반대로 이미지의 크기가 크면 매번 발생할 것 입니다.) 왜냐하면 <code>response</code> 가 아직 제공되지 않았기 때문입니다. 따라서 개발자는 <code>response</code> 가 반환되기 전 까지 기다리게 처리를 해야합니다.</p> + +<p>JavaScript에서 볼 수 있는 비동기 스타일은 두 가지 유형이 있습니다, 예전 방식인 callbacks 그리고 새로운 방식인 promise-style 코드 입니다. 이제부터 차례대로 살펴보겠습니다.</p> + +<h2 id="Async_callbacks">Async callbacks</h2> + +<p>Async callbacks은 백그라운드에서 코드 실행을 시작할 함수를 호출할 때 인수로 지정된 함수입니다. 백그라운드 코드 실행이 끝나면 callback 함수를 호출하여 작업이 완료됐음을 알리거나, 다음 작업을 실행하게 할 수 있습니다. callbacks을 사용하는 것은 지금은 약간 구식이지만, 여전히 다른 곳에서 사용이 되고있음을 확인할 수 있습니다.</p> + +<p>Async callback 의 예시는 {{domxref("EventTarget.addEventListener", "addEventListener()")}} 'click' 옆의 두 번째 매개변수 입니다. :</p> + +<pre class="brush: js notranslate">btn.addEventListener('click', () => { + alert('You clicked me!'); + + let pElem = document.createElement('p'); + pElem.textContent = 'This is a newly-added paragraph.'; + document.body.appendChild(pElem); +});</pre> + +<p>첫 번째 매개 변수는 이벤트 리스너 유형이며, 두 번째 매개 변수는 이벤트가 실행 될 때 호출되는 콜백 함수입니다.</p> + +<p>callback 함수를 다른 함수의 인수로 전달할 때, 함수의 참조를 인수로 전달할 뿐이지 즉시 실행되지 않고, 함수의 body에서 “called back”됩니다. 정의된 함수는 때가 되면 callback 함수를 실행하는 역할을 합니다.</p> + +<p><a href="/en-US/docs/Web/API/XMLHttpRequest"><code>XMLHttpRequest</code> API</a> (<a href="https://mdn.github.io/learning-area/javascript/asynchronous/introducing/xhr-async-callback.html">run it live</a>, and <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/introducing/xhr-async-callback.html">see the source</a>)를 불러오는 예제를 통해 callback 함수를 쉽게 사용해봅시다. :</p> + +<pre class="brush: js notranslate">function loadAsset(url, type, callback) { + let xhr = new XMLHttpRequest(); + xhr.open('GET', url); + xhr.responseType = type; + + xhr.onload = function() { + callback(xhr.response); + }; + + xhr.send(); +} + +function displayImage(blob) { + let objectURL = URL.createObjectURL(blob); + + let image = document.createElement('img'); + image.src = objectURL; + document.body.appendChild(image); +} + +loadAsset('coffee.jpg', 'blob', displayImage);</pre> + +<p><code>displayImage()</code>함수는 Object URL로 전달되는 Blob을 전달받아, URL이 나탸내는 이미지를 만들어 <code><body></code>에 그립니다. 그러나, 우리는 <code>loadAsset()</code> 함수를 만들고 "url", "type" 그리고 "callback"을 매개변수로 받습니다. <code>XMLHttpRequest</code> (줄여서 "XHR") 를 사용하여 전달받은 URL에서 리소스를 가져온 다음 callback으로 응답을 전달하여 작업을 수행합니다. 이 경우 callback은 callback 함수로 넘어가기 전, 리소스 다운로드를 완료하기 위해 XHR 요청이 진행되는 동안 대기합니다. (<code><a href="/en-US/docs/Web/API/XMLHttpRequestEventTarget/onload">onload</a></code> 이벤트 핸들러 사용)</p> + +<p>Callbacks은 다재다능 합니다. 함수가 실행되는 순서, 함수간에 어떤 데이터가 전달되는지를 제어할 수 있습니다. 또한 상황에 따라 다른 함수로 데이터를 전달할 수 있습니다. 따라서 응답받은 데이터에 따라 (<code>processJSON()</code>, <code>displayText()</code>등) 어떤 작업을 수행할지 지정할 수 있습니다.</p> + +<p>모든 callback이 비동기인 것은 아니라는 것에 유의하세요 예를 들어 {{jsxref("Array.prototype.forEach()")}} 를 사용하여 배열의 항목을 탐색할 때가 있습니다. (<a href="https://mdn.github.io/learning-area/javascript/asynchronous/introducing/foreach.html">see it live</a>, and <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/introducing/foreach.html">the source</a>):</p> + +<pre class="brush: js notranslate">const gods = ['Apollo', 'Artemis', 'Ares', 'Zeus']; + +gods.forEach(function (eachName, index){ + console.log(index + '. ' + eachName); +});</pre> + +<p>이 예제에선 그리스 신들의 배열을 탐색하여 인덱스 넘버와 그 값을 콘솔에 출력합니다. <code>forEach()</code> 매개변수는 callback 함수이며, callback 함수는 배열 이름과 인덱스 총 두 개의 매개변수가 있습니다. 그러나, 여기선 비동기로 처리되지 않고 즉시 실행됩니다..</p> + +<h2 id="Promises">Promises</h2> + +<p>Promises 모던 Web APIs에서 보게 될 새로운 코드 스타일 입니다. 좋은 예는 <code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch">fetch()</a></code> API 입니다. <code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch">fetch()</a></code>는 {{domxref("XMLHttpRequest")}}보다 좀 더 현대적인 버전 입니다. 아래 <a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Fetching_data">Fetching data from the server</a> 예제에서 빠르게 살펴볼까요? :</p> + +<pre class="brush: js notranslate">fetch('products.json').then(function(response) { + return response.json(); +}).then(function(json) { + products = json; + initialize(); +}).catch(function(err) { + console.log('Fetch problem: ' + err.message); +});</pre> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: You can find the finished version on GitHub (<a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/fetching-data/can-store-xhr/can-script.js">see the source here</a>, and also <a href="https://mdn.github.io/learning-area/javascript/apis/fetching-data/can-store-xhr/">see it running live</a>).</p> +</div> + +<p><code>fetch</code><code>()</code> 는 단일 매개변수만 전달받습니다. — 네트워크에서 가지고 오고 싶은 리소스의 URL — 그리고 <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">promise</a>로 응답합니다. promise 는 비동기 작업이 성공 했는지 혹은 실패했는지를 나타내는 하나의 오브젝트 입니다. 즉 성공/실패 의 분기점이 되는 중간의 상태라고 표현할 수 있죠. 왜 promise라는 이름이 붙었는지 잠깐 살펴보자면.. "내가 할수 있는 한 빨리 너의 요청의 응답을 가지고 돌아간다고 약속(promise)할게" 라는 브라우저의 표현방식 이어서 그렇습니다.</p> + +<p>이 개념에 익숙해 지기 위해서는 연습이 필요합니다.; 마치 {{interwiki("wikipedia", "Schrödinger's cat")}}(슈뢰딩거의 고양이) 처럼 느껴질 수 있습니다. 위의 예제에서도 발생 가능한 결과 중 아직 아무것도 발생하지 않았기 때문에, 미래에 어떤 시점에서 <code>fetch()</code>작업이 끝났을때 어떤 작업을 수행 시키기 위해 두 가지 작업이 필요합니다. 예제에선 <code>fetch()</code> 마지막에 세 개의 코드 블럭이 더 있는데 이를 살펴보겠습니다. :</p> + +<ul> + <li>두 개의 <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then">then()</a></code> 블럭: 두 함수 모두 이전 작업이 성공했을때 수행할 작업을 나타내는 callback 함수 입니다. 그리고 각 callback함수는 인수로 이전 작업의 성공 결과를 전달받습니다. 따라서 성공했을때의 코드를 callback 함수 안에 작성하면 됩니다. 각 <code>.then()</code> 블럭은 서로 다른 promise를 반환합니다. 이 말은 <code>.then()</code> 을 여러개 사용하여 연쇄적으로 작업을 수행하게 할 수 있음을 말합니다. 따라서 여러 비동기 작업을 차례대로 수행할 수 있습니다.</li> + <li><code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch">catch()</a></code> 블럭은 <code>.then()</code> 이 하나라도 실패하면 동작합니다. — 이는 동기 방식의 <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/try...catch">try...catch</a></code> 블럭과 유사합니다. error 오브젝트는 <code>catch()</code>블럭 안에서 사용할 수 있으며, 발생한 오류를 보고하는 용도로 사용할 수 있습니다. 그러나 <code>try...catch</code> 는 나중에 배울 <a href="/en-US/docs/Learn/JavaScript/Asynchronous/Async_await">async/await</a>에서는 동작하지만, promise와 함께 동작할 수 없음을 알아두세요.</li> +</ul> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: You'll learn a lot more about promises later on in the module, so don't worry if you don't understand them fully yet.</p> +</div> + +<h3 id="The_event_queue">The event queue</h3> + +<p>promise와 같은 비동기 작업은 <strong>event queue</strong>에 들어갑니다. 그리고 main thread가 끝난 후 실행되어 후속 JavaScript 코드가 차단되는것을 방지합니다. queued 작업은 가능한 빨리 완료되어 JavaScript 환경으로 결과를 반환해줍니다.</p> + +<h3 id="Promises_vs_callbacks">Promises vs callbacks</h3> + +<p>Promises 는 old-style callbacks과 유사한 점이 있습니다. 기본적으로 callback을 함수로 전달하는 것이 아닌 callback함수를 장착하고 있는 returned된 오브젝트 입니다.</p> + +<p>그러나 Promise는 비동기 작업을 처리함에 있어서 old-style callbacks 보다 더 많은 이점을 가지고 있습니다. :</p> + +<ul> + <li>여러 개의 연쇄 비동기 작업을 할 때 앞서 본 예제처럼 <code>.then()</code> 을 사용하여 결과값을 다음 작업으로 넘길 수 있습니다. callbacks으로 이를 사용하려면 더 어렵습니다. 또한 "파멸의 피라미드" (<a href="http://callbackhell.com/">callback hell</a>로 잘 알려진)을 종종 마주칠 수 있습니다.</li> + <li>Promise callbacks은 event queue에 배치되는 엄격한 순서로 호출됩니다.</li> + <li>에러 처리가 더 간결해집니다. — 모든 에러를 코드 블럭의 마지막 부분에 있는 단 한개의 <code>.catch()</code> 블럭으로 처리할 수 있습니다. 이 방법은 피라미드의 각 단계에서 에러를 핸들링하는 것 보다 더 간단합니다..</li> + <li>구식 callback은 써드파티 라이브러리에 전달될 때 함수가 어떻게 실행되어야 하는 방법을 상실하는 반면 Promise는 그렇지 않습니다.</li> +</ul> + +<h2 id="The_nature_of_asynchronous_code">The nature of asynchronous code</h2> + +<p>코드 실행 순서를 완전히 알지 못할 때 발생하는 현상과 비동기 코드를 동기 코드처럼 취급하려고 하는 문제를 살펴보면서 비동기 코드의 특성을 더 살펴봅시다 아래 예제는 이전에 봤던 예제와 유사합니다. (<a href="https://mdn.github.io/learning-area/javascript/asynchronous/introducing/async-sync.html">see it live</a>, and <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/introducing/async-sync.html">the source</a>). 한가지 다른 점은 코드가 실행순서를 보여주기 위해 {{domxref("console.log()")}} 를 추가했습니다.</p> + +<pre class="brush: js notranslate">console.log ('Starting'); +let image; + +fetch('coffee.jpg').then((response) => { + console.log('It worked :)') + return response.blob(); +}).then((myBlob) => { + let objectURL = URL.createObjectURL(myBlob); + image = document.createElement('img'); + image.src = objectURL; + document.body.appendChild(image); +}).catch((error) => { + console.log('There has been a problem with your fetch operation: ' + error.message); +}); + +console.log ('All done!');</pre> + +<p>브라우저는 코드를 실행하기 시작할 것이고, 맨 처음 나타난 (<code>Starting</code>) 글씨가 써진 <code>console.log()</code> 후 <code>image</code> 변수를 만들 것 입니다.</p> + +<p>다음으로 <code>fetch()</code> block 으로 이동하여 코드를 실행하려고 할 것 입니다. <code>fetch()</code> 덕분에 blocking없이 비동기 적으로 코드가 실행되겠죠. 블럭 내에서 promise와 관련된 작업이 끝나면 다음 작업으로 이어질 것 입니다. 그리고 마지막으로 (<code>All done!</code>) 가 적혀있는 <code>console.log()</code> 에서 메시지를 출력할 것 입니다.</p> + +<p><code>fetch()</code> 블럭 작업이 작업을 완전히 끝내고 마지막 <code>.then()</code> 블럭에 도달해야 <code>console.log()</code> 의 (<code>It worked :)</code>) 메시지가 나타납니다. 그래서 메시지의 순서는 코드에 적혀있는 대로 차례대로 나타나는게 아니라 순서가 약간 바뀌어서 나타납니다 :</p> + +<ul> + <li>Starting</li> + <li>All done!</li> + <li>It worked :)</li> +</ul> + +<p>이 예가 어렵다면 아래의 다른 예를 살펴보세요 :</p> + +<pre class="brush: js notranslate">console.log("registering click handler"); + +button.addEventListener('click', () => { + console.log("get click"); +}); + +console.log("all done");</pre> + +<p>이전 예제와 매우 유사한 예제 입니다. — 첫 번째와 세 번째<code>console.log()</code> 메시지는 콘솔창에 바로 출력됩니다. 그러나 두 번째 메시지는 누군가가 버튼을 클릭하기 전엔 콘솔에 표시되지 않죠. 위의 예제의 차이라면 두 번쩨 메시지가 어떻게 잠시 blocking이 되는지 입니다. 첫 예제는 Promise 체이닝 때문에 발생하지만 두 번째 메시지는 클릭 이벤트를 대기하느라고 발생합니다.</p> + +<p>less trivial 코드 예제에서 이러한 설정을 문제를 유발할 수 있습니다. — 비동기 코드 블럭에서 반환된 결과를 동기화 코드 블럭에 사용할 수 없습니다. 위의 에시에서 <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">image</span></font> 변수가 그 예시 입니다. 브라우저가 동기화 코드 블럭을 처리하기 전에 비동기 코드 블럭 작업이 완료됨을 보장할 수 없습니다.</p> + +<p>어떤 의미인지 확인을 하려면 <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/introducing/async-sync.html">our example</a>을 컴퓨터에 복사한 후 마지막 <code>console.log()</code> 를 아래처럼 고쳐보세요:</p> + +<pre class="brush: js notranslate">console.log ('All done! ' + image.src + 'displayed.');</pre> + +<p>고치고 나면 콘솔창에서 아래와 같은 에러가 뜨는것을 확인할 수 있습니다. :</p> + +<pre class="notranslate"><span class="message-body-wrapper"><span class="message-flex-body"><span class="devtools-monospace message-body">TypeError: image is undefined; can't access its "src" property</span></span></span></pre> + +<p>브라우저가 마지막 <code>console.log()</code> 를 처리할 때, <code>fetch()</code> 블럭이 완료되지 않아 <code>image</code> 변수에 결과가 반환되지 않았기 때문입니다.</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: For security reasons, you can't <code>fetch()</code> files from your local filesystem (or run other such operations locally); to run the above example locally you'll have to run the example through a <a href="/en-US/docs/Learn/Common_questions/set_up_a_local_testing_server">local webserver</a>.</p> +</div> + +<h2 id="Active_learning_make_it_all_async!">Active learning: make it all async!</h2> + +<p>위의 <code>fetch()</code> 예시에서 마지막<code>console.log()</code>도 순서대로 나타나도록 고칠 수 있습니다. 마지막 <code>console.log()</code> 도 비동기로 작동시키면 됩니다. 마지막 <code>.then()</code> 블럭의 마지막에 다시 작성하거나, 새로운 블럭을 만들면 콘솔에 순서대로 나타날 것 입니다. 지금 바로 고쳐보세요!</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: If you get stuck, you can <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/introducing/async-sync-fixed.html">find an answer here</a> (see it <a href="https://mdn.github.io/learning-area/javascript/asynchronous/introducing/async-sync-fixed.html">running live</a> also). You can also find a lot more information on promises in our <a href="/en-US/docs/Learn/JavaScript/Asynchronous/Promises">Graceful asynchronous programming with Promises</a> guide, later on in the module.</p> +</div> + +<h2 id="Conclusion">Conclusion</h2> + +<p>In its most basic form, JavaScript is a synchronous, blocking, single-threaded language, in which only one operation can be in progress at a time. But web browsers define functions and APIs that allow us to register functions that should not be executed synchronously, and should instead be invoked asynchronously when some kind of event occurs (the passage of time, the user's interaction with the mouse, or the arrival of data over the network, for example). This means that you can let your code do several things at the same time without stopping or blocking your main thread.</p> + +<p>Whether we want to run code synchronously or asynchronously will depend on what we're trying to do.</p> + +<p>There are times when we want things to load and happen right away. For example when applying some user-defined styles to a webpage you'll want the styles to be applied as soon as possible.</p> + +<p>If we're running an operation that takes time however, like querying a database and using the results to populate templates, it is better to push this off the main thread and complete the task asynchronously. Over time, you'll learn when it makes more sense to choose an asynchronous technique over a synchronous one.</p> + +<ul> +</ul> + +<p>{{PreviousMenuNext("Learn/JavaScript/Asynchronous/Concepts", "Learn/JavaScript/Asynchronous/Timeouts_and_intervals", "Learn/JavaScript/Asynchronous")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Concepts">General asynchronous programming concepts</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Introducing">Introducing asynchronous JavaScript</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Timeouts_and_intervals">Cooperative asynchronous JavaScript: Timeouts and intervals</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Promises">Graceful asynchronous programming with Promises</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Async_await">Making asynchronous programming easier with async and await</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Choosing_the_right_approach">Choosing the right approach</a></li> +</ul> diff --git a/files/ko/learn/javascript/asynchronous/promises/index.html b/files/ko/learn/javascript/asynchronous/promises/index.html new file mode 100644 index 0000000000..bf7a5a0f04 --- /dev/null +++ b/files/ko/learn/javascript/asynchronous/promises/index.html @@ -0,0 +1,588 @@ +--- +title: Graceful asynchronous programming with Promises +slug: Learn/JavaScript/Asynchronous/Promises +translation_of: Learn/JavaScript/Asynchronous/Promises +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Asynchronous/Timeouts_and_intervals", "Learn/JavaScript/Asynchronous/Async_await", "Learn/JavaScript/Asynchronous")}}</div> + +<p class="summary"><span class="seoSummary"><strong>Promises</strong> 는 이전 작업이 완료될 때 까지 다음 작업을 연기 시키거나, 작업실패를 대응할 수 있는 비교적 새로운 JavaScript 기능입니다.</span> Promise는 비동기 작업 순서가 정확하게 작동되게 도움을 줍니다. 이번 문서에선 Promise가 어떻게 동작하는지, 웹 API와 어떻게 사용할 수 있는지 그리고 직접 코드를 만들어 볼것 입니다. </p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Prerequisites:</th> + <td>Basic computer literacy, a reasonable understanding of JavaScript fundamentals.</td> + </tr> + <tr> + <th scope="row">Objective:</th> + <td>To understand promises and how to use them.</td> + </tr> + </tbody> +</table> + +<h2 id="What_are_promises">What are promises?</h2> + +<p>앞서서 <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promises</a> 를 미리 봤지만, 지금부턴 좀더 깊이있게 들여다 볼 차례 입니다..</p> + +<p>Promise는 어떤 작업의 중간상태를 나타내는 오브젝트 입니다. — 미래에 어떤 종류의 결과가 반환됨을 <em>promise</em> (약속) 해주는 오브젝트라고 보면 됩니다. Promise는 작업이 완료되어 결과를 반환해주는 정확한 시간을 보장해주지는 않지만, 사용할 수 있는 결과를 반환했을때 프로그래머의 의도대로 다음 코드를 진행 시키거나, 에러가 발생했을 때 그 에러를 우아하게/깔끔하게 처리할 수 있습니다.</p> + +<p>일반적으로 우리는 비동기 작업이 결과를 반환하는데 얼마의 시간이 걸리는지 보다는(<em>작업 시간이 매우 오래 걸리지 않는 한</em>) 그 결과를 사용할 수 있는지 여부에 더 관심이 있습니다. 물론 나머지 코드 블럭을 막지 않는다는 것에 있어서 매우 좋습니다.</p> + +<p>우리가 Promise로 가장 많이 할 작업중 하나는 Promise를 반환하는 웹API를 사용하는 것 입니다. 가상의 비디오 채팅 애플리케이션이 있다고 해봅시다. 애플리케이션에는 친구 목록이 있고 각 친구 목록 옆의 버튼을 클릭하면 해당 친구와 비디오 채팅을 시작합니다.</p> + +<p>그 버튼은 사용자 컴퓨터의 카메라와 마이크를 사용하기 위해 {{domxref("MediaDevices.getUserMedia", "getUserMedia()")}} 를 호출합니다. <code>getUserMedia()</code> 는 사용자가 이러한 장치를 사용할 수 있는 권한을 가지고 있는지 확인해야 하고, 어떤 마이크와 카메라를 사용할 것인지 (혹은 음성 통화인지, 아니면 다른 옵션들이 있는지)를 체크해야하기 때문에 모든 결정이 내려질 때 까지 다음 작업을 차단할 수 있습니다. 또한 카메라와 마이크가 작동하기 전 까지 다음 작업을 차단할수도 있습니다.</p> + +<p><code>getUserMedia()</code> 는 브라우저의 main thread에서 실행되므로 <code>getUserMedia()</code> 결과가 반환되기 전 까지 후행 작업이 모두 차단됩니다. 이러한 blocking은 우리가 바라는게 아닙니다. Promise가 없으면 이러한 결정이 내려지기 전 까지 브라우저의 모든 것을 사용할 수 없게됩니다. 따라서 사용자가 선택한 장치를 활성화하고 소스에서 선택된 스트림에 대해{{domxref("MediaStream")}} 직접 반환하는 대신 <code>getUserMedia()</code> 는 모든 장치가 사용 가능한 상태가 되면 {{domxref("MediaStream")}}이 포함된 {{jsxref("promise")}}를 반환합니다.</p> + +<p>비디오 채팅 애플리케이션의 코드는 아래처럼 작성할 수 있습입니다. :</p> + +<pre class="brush: js notranslate">function handleCallButton(evt) { + setStatusMessage("Calling..."); + navigator.mediaDevices.getUserMedia({video: true, audio: true}) + .then(chatStream => { + selfViewElem.srcObject = chatStream; + chatStream.getTracks().forEach(track => myPeerConnection.addTrack(track, chatStream)); + setStatusMessage("Connected"); + }).catch(err => { + setStatusMessage("Failed to connect"); + }); +} +</pre> + +<p>이 기능은 상태 메시지에 "Calling..."을 출력하는 <code>setStatusMessage()</code> 함수로 시작하며 통화가 시도되고 있음을 나타냅니다. 그런 다음 <code>getUserMedia()</code>을 호출하여 비디오와 오디오 트랙이 모두 있는 스트림 요청을 합니다. 그리고 스트림을 획득하면 카메라에서 나오는 스트림을 "self view,"로 표시하기 위해 video엘리먼트를 설정합니다. 그리고 각 스트림의 트랙을 가져가 다른 사용자와의 연결을 나타내는 <a href="/en-US/docs/Web/API/WebRTC_API">WebRTC</a> {{domxref("RTCPeerConnection")}}에 추가합니다. 그리고 마지막으로 상태 메시지를 "Connected"로 업데이트 합니다.</p> + +<p><code>getUserMedia()</code> 가 실패하면, <code>catch</code> 블럭이 실행되며, <code>setStatusMessage()</code> 를 사용하여 상태창에 오류 메시지를 표시합니다.</p> + +<p>여기서 중요한건 <code>getUserMedia()</code>는 카메라 스트림이 아직 확보되지 않았음에도 거의 즉시 반환을 해줬다는 것 입니다. <code>handleCallButton()</code> 함수가 자신을 호출한 코드로 결과를 이미 반환을 했더라도 <code>getUserMedia()</code>의 작업이 종료되면 프로그래머가 작성한 다음 핸들러를 호출할 것 입니다. 앱이 스트리밍을 했다고 가정하지 않는 한 계속 실행될 수 있습니다.</p> + +<div class="blockIndicator note"> +<p><strong>Note:</strong> You can learn more about this somewhat advanced topic, if you're interested, in the article <a href="/docs/Web/API/WebRTC_API/Signaling_and_video_calling">Signaling and video calling</a>. Code similar to this, but much more complete, is used in that example.</p> +</div> + +<h2 id="The_trouble_with_callbacks">The trouble with callbacks</h2> + +<p>Promise가 왜 좋은지 이해하기 위해 구식 callbacks을 살펴보고 어떤게 문제인지 파악 해보겠습니다.</p> + +<p>피자를 주문한다고 생각해봅시다. 피자를 잘 주문하려면 몇 가지 단계를 진행해야 합니다. 토핑 위에 도우를 올리고 치즈를 뿌리는 등 각 단계가 뒤죽박죽 이거나 혹은 도우를 반죽하고 있는데 그 위에 토마토소스를 바르는 등 이전 작업이 끝나지 않고 다음 작업을 진행하는 것은 말이 안 됩니다. :</p> + +<ol> + <li>먼저 원하는 토핑을 고릅니다. 결정 장애가 심할 경우 토핑을 고르는데 오래 걸릴 수 있습니다. 또한 마음을 바꿔 피자 대신 카레를 먹으려고 가게를 나올 수 있습니다.</li> + <li>그다음 피자를 주문합니다. 식당이 바빠서 피자가 나오는 데 오래 걸릴 수 있고, 마침 재료가 다 떨어졌으면 피자를 만들 수 없다고 할 것 입니다.</li> + <li>마지막으로 피자를 받아서 먹습니다. 그런데! 만약 지갑을 놓고 와서 돈을 내지 못한다면 피자를 먹지 못할 수 있습니다.</li> +</ol> + +<p>구식 <a href="/en-US/docs/Learn/JavaScript/Asynchronous/Introducing#Callbacks">callbacks</a>을 사용하면 아래와 같은 모습의 코드가 나타날것 입니다. :</p> + +<pre class="brush: js notranslate">chooseToppings(function(toppings) { + placeOrder(toppings, function(order) { + collectOrder(order, function(pizza) { + eatPizza(pizza); + }, failureCallback); + }, failureCallback); +}, failureCallback);</pre> + +<p>이런 코드는 읽기도 힘들 뿐 아니라 (종종 "콜백 지옥" 이라 불림), <code>failureCallback()</code> 을 여러 번 작성해야 하며 또한 다른 문제점도 가지고 있습니다.</p> + +<h3 id="Improvements_with_promises">Improvements with promises</h3> + +<p>위의 상황에서 Promise를 사용하면 읽기, 작성, 실행 모두 다 쉬워집니다. callback 대신 비동기 Promise를 사용하면 아래처럼 작성할 수 있습니다. :</p> + +<pre class="brush: js notranslate">chooseToppings() +.then(function(toppings) { + return placeOrder(toppings); +}) +.then(function(order) { + return collectOrder(order); +}) +.then(function(pizza) { + eatPizza(pizza); +}) +.catch(failureCallback);</pre> + +<p>보기에 훨씬 더 좋군요! — 이렇게 작성하면 앞으로 어떤 일이 일어날지 쉽게 예측 가능합니다. 그리고 단 한개의 <code>.catch()</code> 을 사용하여 모든 에러를 처리합니다. 그리고 main thread를 차단하지 않습니다. (그래서 피자를 주문하고 기다리는 동안 하던 게임을 마저 할 수 있습니다.), 또한 각 함수가 실행되기 전 이전 작업이 끝날때까지 기다립니다. 이런식으로 여러 개의 비동기 작업을 연쇄적으로 처리할 수 있습니다. 왜냐햐면 각 <code>.then()</code> 블럭은 자신이 속한 블럭의 작업이 끝났을 때의 결과를 새로운 Promise 반환해주기 때문입니다. 어때요, 참 쉽죠?</p> + +<p>화살표 함수를 사용하면 코드를 조금 더 간단하게 고칠 수 있습니다. :</p> + +<pre class="brush: js notranslate">chooseToppings() +.then(toppings => + placeOrder(toppings) +) +.then(order => + collectOrder(order) +) +.then(pizza => + eatPizza(pizza) +) +.catch(failureCallback);</pre> + +<p>혹은 아래처럼 표현할 수 있습니다. :</p> + +<pre class="brush: js notranslate">chooseToppings() +.then(toppings => placeOrder(toppings)) +.then(order => collectOrder(order)) +.then(pizza => eatPizza(pizza)) +.catch(failureCallback);</pre> + +<p>화살표 함수의 <code>() => x</code> 표현은 <code>() => { return x; }</code>의 약식 표현이므로 잘 작동합니다.</p> + +<p>함수는 arguments를 직접 전달 하므로 함수처럼 표현하지 않고 아래와 같이 작성할 수도 있습니다. :</p> + +<pre class="brush: js notranslate">chooseToppings().then(placeOrder).then(collectOrder).then(eatPizza).catch(failureCallback);</pre> + +<p>그런데 이렇게 작성하면 읽기가 쉽지 않습니다. 사용자의 코드가 지금의 예제보다 더 복잡하다면 위의 방법은 사용하기 힘듭니다.</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: 다음 장에서 배울 <code>async</code>/<code>await</code> 문법으로 좀 더 간결화 할 수 있습니다.</p> +</div> + +<p>Promise는 이벤트 리스너와 유사하지만 몇 가지 다른점이 있습니다. :</p> + +<ul> + <li>Promise는 한번에 성공/실패 중 하나의 결과값을 가집니다. 하나의 요청에 두 번 성공하고나 실패할 수 없습니다. 또한 이미 성공한 작업이 다시 실패로 돌아갈 수 없고 실패한 작업이 성공으로 돌아갈 수 없습니다.</li> + <li>If a promise has succeeded or failed and you later add a success/failure callback, the correct callback will be called, even though the event took place earlier.</li> +</ul> + +<h2 id="Explaining_basic_promise_syntax_A_real_example">Explaining basic promise syntax: A real example</h2> + +<p>모던 웹 API는 잠재적으로 긴 작업을 수행하는 함수에 Promise를 사용하므로 Promise가 무엇인지 이해하는것은 매우 중요합니다. 현대적인 웹 기술을 사용하려면 Promise를 사용해야합니다. 챕터의 후반부에서 직접 Promise를 만들어보겠지만, 지금은 일단 웹 API에서 접할 수 있는 몇 가지 예제를 살펴보겠습니다.</p> + +<p>첫 번째로, 웹에서 이미지를 가져오기 위하여 <code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch">fetch()</a></code> 메서드를 사용할 때 입니다.{{domxref("Body.blob", "blob()")}} 메서드는 fetch가 응답한 원시 body컨텐츠를 {{domxref("Blob")}} 오브젝트로 변환시켜주고{{htmlelement("img")}} 엘리먼트에 표현합니다. 이예제는 <a href="/en-US/docs/Learn/JavaScript/Asynchronous/Introducing#Asynchronous_JavaScript">first article of the series</a>유사합니다. 다만 Promise를 사용하기 위해 약간의 변경을 하겠습니다.</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: The following example will not work if you just run it directly from the file (i.e. via a <code>file://</code> URL). You need to run it through a <a href="/en-US/docs/Learn/Common_questions/set_up_a_local_testing_server">local testing server</a>, or use an online solution such as <a href="https://glitch.com/">Glitch</a> or <a href="/en-US/docs/Learn/Common_questions/Using_Github_pages">GitHub pages</a>.</p> +</div> + +<ol> + <li> + <p>먼저 <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/getting-started/index.html">simple HTML template</a> 와 fetch할 이미지인 <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/coffee.jpg">sample image file</a> 을 다운받습니다.</p> + </li> + <li> + <p>HTML {{htmlelement("body")}} 하단에 {{htmlelement("script")}} 엘리먼트를 삽입합니다.</p> + </li> + <li> + <p>{{HTMLElement("script")}} 엘리먼트 안에 아래와 같이 코드를 작성합니다. :</p> + + <pre class="brush: js notranslate">let promise = fetch('coffee.jpg');</pre> + + <p><code>fetch()</code> 메서드를 호출하여, 네트워크에서 fetch할 이미지의 URL을 매개변수로 전달합니다. 두 번째 매개변수를 사용할 수 있지만, 지금은 우선 간단하게 하나의 매개변수만 사용하겠습니다. 코드를 더 살펴보면 <code>promise</code>변수에 <code>fetch()</code> 작업으로 반환된 Promise 오브젝트를 저장하고 있습니다. 이전에 말했듯이, 지금 오브젝트는 성공도 아니고 실패도 아닌 중간 상태를 저장하고 있습니다. 공식적으로는 <strong>pending</strong>상태라고 부릅니다.</p> + </li> + <li> + <p>작업이 성공적으로 진행될 때를 대응하기 위해 (이번 예제에선 {{domxref("Response")}} 가 반환될 때 입니다. ), 우리는 Promise 오브젝트의 <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then">.then()</a></code> 메서드를 호출합니다. <code>.then()</code> 블럭 안의 callback은 (<strong>executor </strong>라고 부름) Promise가 성공적으로 완료되고{{domxref("Response")}} 오브젝트를 반환할 때만 실행합니다. — 이렇게 성공한 Promise의 상태를 <strong>fulfilled</strong>라고 부릅니다. 그리고 반환된 {{domxref("Response")}} 오브젝트를 매개변수로 전달합니다.</p> + + <div class="blockIndicator note"> + <p><strong>Note</strong>: The way that a <code>.then()</code> block works is similar to when you add an event listener to an object using <code>AddEventListener()</code>. It doesn't run until an event occurs (when the promise fulfills). The most notable difference is that a .then() will only run once for each time it is used, whereas an event listener could be invoked multiple times.</p> + </div> + + <p>그리고 즉시 <code>blob()</code> 메서드를 실행하여 Response Body가 완전히 다운로드 됐는지 확인합니다. 그리고 Response Body가 이용 가능할 때 추가 작업을 할 수 있는 <code>Blob</code> 오브젝트로 변환시킵니다. 해당 코드는 아래와 같이 작성할 수 있습니다. :</p> + + <pre class="brush: js notranslate">response => response.blob()</pre> + + <p>위의 코드는 아래의 코드를 축약한 형태입니다. </p> + + <pre class="brush: js notranslate">function(response) { + return response.blob(); +}</pre> + + <p>이제 추가 설명은 충븐하므로, JavaScript의 첫 번째 줄 아래에 다음과 같은 라인을 추가하세요.</p> + + <pre class="brush: js notranslate">let promise2 = promise.then(response => response.blob());</pre> + </li> + <li> + <p>각 <code>.then()</code> 을 호출하면 새로운 Promise를 만드는데, 이는 매우 유용합니다. 왜냐하면 <code>blob()</code> 메서드도 Promise를 반환하기 때문에, 두 번째 Promise의 <code>.then()</code> 메서드를 호출함으로써 이행시 반환되는 <code>Blob</code> 오브젝트를 처리할 수 있습니다. 한 가지 메서드를 실행하여 결과를 반환하는 것보다 Blob에 좀 더 복잡한 일을 추가하고 싶습니다. 이럴때는 중괄호{ }로 묶습니다. (그렇지 않으면 에러가 발생합니다.).</p> + + <p>이어서 아래와 같은 코드를 추가합니다.:</p> + + <pre class="brush: js notranslate">let promise3 = promise2.then(myBlob => { + +})</pre> + </li> + <li> + <p>이제 executor 함수를 아래와 같이 채워넣습니다. 중괄호 안에 작성하면 됩니다. :</p> + + <pre class="brush: js notranslate">let objectURL = URL.createObjectURL(myBlob); +let image = document.createElement('img'); +image.src = objectURL; +document.body.appendChild(image);</pre> + + <p>여기서 우리는 두 번째 Promise가 fulfills일 때 반횐된 Blob을 매개변수로 전달받는 {{domxref("URL.createObjectURL()")}} 메서드를 실행하고 있습니다. 이렇게 하면 오브젝트가 가지고있는 URL이 반환됩니다. 그 다음 {{htmlelement("img")}} 엘리먼트를 만들고, 반환된 URL을 <code>src</code> 속성에 지정하여 DOM에 추가합니다. 이렇게 하면 페이지에 그림이 표시됩니다.</p> + </li> +</ol> + +<p>If you save the HTML file you've just created and load it in your browser, you'll see that the image is displayed in the page as expected. Good work!</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: You will probably notice that these examples are somewhat contrived. You could just do away with the whole <code>fetch()</code> and <code>blob()</code> chain, and just create an <code><img></code> element and set its <code>src</code> attribute value to the URL of the image file, <code>coffee.jpg</code>. We did, however, pick this example because it demonstrates promises in a nice simple fashion, rather than for its real-world appropriateness.</p> +</div> + +<h3 id="Responding_to_failure">Responding to failure</h3> + +<p>현재 에러가 발생했을 때 어떻게 처리를 해야할 지 작성된 코드가 없기때문에 코드를 조금만 더 추가하여 좀 더 완벽하게 작성해봅시다. (Promise에서 에러가 발생한 상태를 <strong>rejects</strong>라 부릅니다). 이전에 봤던대로 <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch">.catch()</a></code> 블럭을 추가하여 오류를 핸들링 할 수 있습니다. 아래처럼 말이죠 :</p> + +<pre class="brush: js notranslate">let errorCase = promise3.catch(e => { + console.log('There has been a problem with your fetch operation: ' + e.message); +});</pre> + +<p>에러 메시지를 확인하고 싶으면 잘못된 url을 지정해보세요, 개발자 도구 콘솔에서 에러를 확인할 수 있을것 입니다.</p> + +<p>물론 <code>.catch()</code> 블록 없이 코드를 작동시킬 수 있습니다. 하지만 좀 더 깊게 생각해보면 <code>.catch()</code> 블록이 없으면 어떤 에러가 발생했는지, 어떻게 해결해야 하는지 디버깅이 어렵습니다. 실제 앱에서 <code>.catch()</code> 을 사용하여 이미지 가져오기를 다시 실행하거나, 기본 이미지를 표시하는 등 작업을 지시할 수 있습니다.</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: You can see <a href="https://mdn.github.io/learning-area/javascript/asynchronous/promises/simple-fetch.html">our version of the example live</a> (see the <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/simple-fetch.html">source code</a> also).</p> +</div> + +<h3 id="Chaining_the_blocks_together">Chaining the blocks together</h3> + +<p>위에서 사용한 코드는 작업이 어떻게 처리되는지 명확하게 보여주기 위해 매우 길게 코드를 작성했습니다. 이전 글에서 봤듯이, <code>.then()</code> 블럭을 사용하여 연쇄 작업을 진행할 수 있습니다. (또한 <code>.catch()</code> 블럭을 사용하여 에러 처리도 했지요). 앞선 예제의 코드는 아래와 같이 작성할 수도 있습니다. (see also <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/simple-fetch-chained.html">simple-fetch-chained.html</a> on GitHub):</p> + +<pre class="brush: js notranslate">fetch('coffee.jpg') +.then(response => response.blob()) +.then(myBlob => { + let objectURL = URL.createObjectURL(myBlob); + let image = document.createElement('img'); + image.src = objectURL; + document.body.appendChild(image); +}) +.catch(e => { + console.log('There has been a problem with your fetch operation: ' + e.message); +});</pre> + +<p>fulfilled promise 결과에 의해 반환된 값이 다음 <code>.then()</code> 블록의 executor 함수가 가진 파라미터로 전달 된다는 것을 꼭 기억하세요.</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: <code>.then()</code>/<code>.catch()</code> blocks in promises are basically the async equivalent of a <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/try...catch">try...catch</a></code> block in sync code. Bear in mind that synchronous <code>try...catch</code> won't work in async code.</p> +</div> + +<h2 id="Promise_terminology_recap">Promise terminology recap</h2> + +<p>위의 섹션에서 다룬 내용은 정말 많습니다. 매우 중요한 내용을 다뤘으므로 개념을 명확히 이해하기 위해 몇번이고 다시 읽어보는게 좋습니다.</p> + +<ol> + <li>Promise가 생성되면 그 상태는 성공도 실패도 아닌 <strong>pending</strong>상태라고 부릅니다..</li> + <li>Promise결과가 반환되면 결과에 상관 없이 <strong>resolved</strong>상태라고 부릅니다.. + <ol> + <li>성공적으로 처리된 Promise는 <strong>fulfilled</strong>상태이다. 이 상태가 되면 Promise 체인의 다음 <code>.then()</code> 블럭에서 사용할 수 있는 값을 반환합니다.. 그리고 <code>.then()</code> 블럭 내부의 executor 함수에 Promise에서 반환된 값이 파라미터로 전달됩니다..</li> + <li>실패한 Promise는 <strong>rejected</strong>상태이다. 이때 어떤 이유(<strong>reason)</strong> 때문에 Promise가 rejected 됐는지를 나타내는 에러 메시지를 포함한 결과가 반환됩니다. Promise 체이닝의 제일 마지막 <code>.catch()</code> 에서 상세한 에러 메시지를 확인할 수 있습니다.</li> + </ol> + </li> +</ol> + +<h2 id="Running_code_in_response_to_multiple_promises_fulfilling">Running code in response to multiple promises fulfilling</h2> + +<p>위의 예제에서 Promise사용의 기초를 확인했습니다. 이제 고급 기능들을 한번 보겠습니다. 제일 먼저 확인해볼 예제는 다음과 같습니다. 연쇄적으로 일어나는 작업은 좋습니다. 그런데 모든 Promise가 fulfilled일 경우 코드를 실행하고 싶은 경우가 있을것 입니다.</p> + +<p>해당 기능을 <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all">Promise.all()</a></code> 이라는 스테틱 메서드를 사용하여 만들 수 있습니다. 이 메서드는 Promise의 배열을 매개변수로 삼고, 배열의 모든 Promise가 fulfil일 때만 새로운 fulfil <code>Promise</code> 오브젝트를 반환합니다. 아래처럼 말이죠 :</p> + +<pre class="brush: js notranslate">Promise.all([a, b, c]).then(values => { + ... +});</pre> + +<p>배열의 모든 Promise가 fulfil 이면, <code>.then()</code> 블럭의 executor 함수로의 매개변수로 Promise 결과의 배열을 전달합니다. <code>Promise.all()</code> 의 Promise의 배열 중 하나라도 reject라면, 전체 결과가 reject가 됩니다.</p> + +<p>이 방법은 매우 유용합니다. 웹 UI의 컨텐츠를 동적인 방법으로 채운다고 생각 해보겠습니다. 대부분 경우에 듬성듬성 내용을 채우기보단, 완전한 내용을 채울것 입니다.</p> + +<p>다른 예제를 만들어서 실행해 보겠습니다.</p> + +<ol> + <li> + <p>이미 만들어진 <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/getting-started/index.html">page template</a>을 다운받으세요 그리고 <code></body></code> 뒤에 <code><script></code> 엘리먼트를 만들어주세요.</p> + </li> + <li> + <p>이미지 그리고 텍스트 파일(<a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/coffee.jpg">coffee.jpg</a>, <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/tea.jpg">tea.jpg</a>, and <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/description.txt">description.txt</a>)을 다운받고 <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/getting-started/index.html">page template</a> 와 같은 경로에 저장해주세요.</p> + </li> + <li> + <p>먼저 Promise를 반환하는 몇 가지 함수를 만들어 <code>Promise.all()</code>로 결과를 반환합니다. 세 개의 <code>fetch()</code> 작업이 끝나고 다음 요청을 진행하고 싶다면 아래 코드처럼 <code>Promise.all()</code>블럭을 작성합니다. :</p> + + <pre class="brush: js notranslate">let a = fetch(url1); +let b = fetch(url2); +let c = fetch(url3); + +Promise.all([a, b, c]).then(values => { + ... +});</pre> + + <p>Promise가 fulfilled가 됐을 때, fulfilment handler 핸들러로 전달된 <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">values</span></font> 매개변수에는 각 <code>fetch()</code> 의 결과로 발생한 세 개의 <code>Response</code> 오브젝트가 들어있습니다 .</p> + + <p>하지만 우리는 단순히 결과만 넘겨주고 싶지 않습니다. 우리는<code>fetch()</code> 언제 끝나는지 보다 불러온 데이터에 더 관심이 있습니다. 그말은 브라우저에 표현할 수 있는 Blob과 텍스트 문자열이 불러와 졌을 때 <code>Promise.all()</code> 블럭을 실행하고 싶다는 것 입니다. <code><script></code> 엘리먼트에 아래와 같이 작성합니다. :</p> + + <pre class="brush: js notranslate">function fetchAndDecode(url, type) { + return fetch(url).then(response => { + if (type === 'blob') { + return response.blob(); + } else if (type === 'text') { + return response.text(); + } + }) + .catch(e => { + console.log('There has been a problem with your fetch operation: ' + e.message); + }); +}</pre> + + <p>살짝 복잡해 보이므로 하나하나 살펴봅시다. :</p> + + <ol> + <li>먼저 fetchAndDecode() 함수를 정의했고 함수의 매개변수로 컨텐츠의 URL과 가져오는 리소스의 타입을 지정합니다.</li> + <li>함수 내부에 첫 번째 예에서 본 것과 유사한 구조를 가진 코드가 있습니다. — <code>fetch()</code> 함수를 호출하여 전달받은 URL에서 리소스를 받아오도록 했습니다. 그리고 다음 Promise를 연쇄적으로 호출하여 디코딩된 (혹은 "읽은") Response Body를 반환하게 합니다. 이전 예에선 Blob만을 가져오기 때문에 <code>blob()</code> 메서드만 썼습니다.</li> + <li>여기에선 이전과 다른 두 가지가 있습니다. : + <ul> + <li>먼저 두 번째 Promise에서는 불러올 리소스의 <code>type</code> 이 무엇인지에 따라 반환받는 데이터가 다릅니다. executor 함수 내부에, 간단한 <code>if ... else if</code> 구문을 사용하여 어떤 종류의 파일을 디코딩해야 하는지에 따라 다른 Promise를 반환하게 했습니다. (이 경우 <code>blob</code> 이나 <code>text</code>밖에 없지만, 이것을 잘 활용하여 다른 코드에 확장하여 적용할 수 있습니다.).</li> + <li>두 번째로, <code>fetch()</code> 호출 앞에 <code>return</code> 키워드를 추가했습니다. 이렇게 하면 Promise 체이닝의 마지막 결과값을 함수의 결과로 반환해 줄 수 있습니다. (이 경우 <code>blob()</code> 혹은 <code>text()</code>메서드에 의해 반환된 Promise 입니다.) 사실상 <code>fetch()</code> 앞의 <code>return</code> 구문은 체이닝 결과를 다시 상단으로 전달하는 행위 입니다.</li> + </ul> + </li> + <li> + <p>블럭의 마지막에는 <code>.catch()</code> 블럭을 추가하여 작업중 발생한 에러를 <code>.all()</code>의 배열로 전달합니다. 아무 Promise에서 reject가 발생하면, catch 블럭은 어떤 Promise에서 에러가 발생했는지 알려줄 것 입니다. <code>.all()</code> (아래쪽에 있는) 블럭의 리소스에 문제가 있지 않는 이상 항상 fulfil일것 입니다. <code>.all</code> 블럭의 마지막 체이닝에 <code>.catch()</code> 블럭을 추가하여 reject됐을때 확인을 할 수 있습니다.</p> + </li> + </ol> + + <p>함수의 body 안에 있는 코드는 비동기적이고 Promise 기반이므로, 전체 함수는 Promise로 작동합니다. — 편리하죠?.</p> + </li> + <li> + <p>다음으로 fetchAndDecode() 함수를 세 번 호출하여 이미지와 텍스트를 가져오고 디코딩 하는 과정을 시작합니다. 그리고 반환된 Promise를 각각의 변수에 저장합니다. 이전 코드에 이어서 아래 코드를 추가하세요. :</p> + + <pre class="brush: js notranslate">let coffee = fetchAndDecode('coffee.jpg', 'blob'); +let tea = fetchAndDecode('tea.jpg', 'blob'); +let description = fetchAndDecode('description.txt', 'text');</pre> + </li> + <li> + <p>다음으로 위의 세 가지 코드가 모두 fulfilled가 됐을 때 원하는 코드를 실행하기 위해 <code>Promise.all()</code> 블럭을 만듭니다. 우선, <code>.then()</code> call 안에 비어있는 executor 를 추가하세요 :</p> + + <pre class="brush: js notranslate">Promise.all([coffee, tea, description]).then(values => { + +});</pre> + + <p>위에서 Promise를 포함하는 배열을 매개 변수로 사용하는 것을 확인할 수 있습니다. executor는 세 가지 Promise가 resolve될 때만 실행될 것 입니다. 그리고 executor가 실행될 때 개별적인 Promise의 결과를 포함하는 [coffee-results, tea-results, description-results] 배열을 매개 변수로 전달받을 것 입니다. (여기선 디코딩된 Response Body 입니다.).</p> + </li> + <li> + <p>마지막으로 executor 함수를 작성합니다. 예제에선 반환된 결과를 별도의 변수로 저장하기 위해 간단한 동기화 코드를 사용합니다. (Blob에서 오브젝트 URLs 생성), 그리고 페이지에 텍스트와 이미지를 표시합니다.</p> + + <pre class="brush: js notranslate">console.log(values); +// Store each value returned from the promises in separate variables; create object URLs from the blobs +let objectURL1 = URL.createObjectURL(values[0]); +let objectURL2 = URL.createObjectURL(values[1]); +let descText = values[2]; + +// Display the images in <img> elements +let image1 = document.createElement('img'); +let image2 = document.createElement('img'); +image1.src = objectURL1; +image2.src = objectURL2; +document.body.appendChild(image1); +document.body.appendChild(image2); + +// Display the text in a paragraph +let para = document.createElement('p'); +para.textContent = descText; +document.body.appendChild(para);</pre> + </li> + <li> + <p>코드를 저장하고 창을 새로고치면 보기엔 좋지 않지만, UI 구성 요소가 모두 표시된 것을 볼 수 있습니다.</p> + </li> +</ol> + +<p>여기서 제공한 코드는 매우 기초적이지만, 내용을 전달하기에는 아주 좋습니다..</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: If you get stuck, you can compare your version of the code to ours, to see what it is meant to look like — <a href="https://mdn.github.io/learning-area/javascript/asynchronous/promises/promise-all.html">see it live</a>, and see the <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/promise-all.html">source code</a>.</p> +</div> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: If you were improving this code, you might want to loop through a list of items to display, fetching and decoding each one, and then loop through the results inside <code>Promise.all()</code>, running a different function to display each one depending on what the type of code was. This would make it work for any number of items, not just three.</p> + +<p>Also, you could determine what the type of file is being fetched without needing an explicit <code>type</code> property. You could, for example, check the {{HTTPHeader("Content-Type")}} HTTP header of the response in each case using <code><a href="/en-US/docs/Web/API/Headers/get">response.headers.get("content-type")</a></code>, and then react accordingly.</p> +</div> + +<h2 id="Running_some_final_code_after_a_promise_fulfillsrejects">Running some final code after a promise fulfills/rejects</h2> + +<p>Promise의 결과가 fulfilled 인지 rejected인지 관계 없이 Promise가 완료된 후 최종 코드 블럭을 실행하려는 경우가 있을 것입니다. 이전에는 아래 예시처럼 <code>.then()</code> 블럭과<code>.catch()</code> 블럭의 callbacks에 아래와 같이 runFinalCode()를 넣었었습니다. :</p> + +<pre class="brush: js notranslate">myPromise +.then(response => { + doSomething(response); + runFinalCode(); +}) +.catch(e => { + returnError(e); + runFinalCode(); +});</pre> + +<p>보다 최근의 현대 브라우저에서는 <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/finally">.finally()</a></code> 메서드를 사용할 수 있습니다. 이 메서드를 Promise 체이닝의 끝에 배치하여 코드 반복을 줄이고 좀 더 우아하게 일을 처리할 수 있습니다. 아래와 같이 마지막 블럭에 적용할 수 있습니다. :</p> + +<pre class="brush: js notranslate">myPromise +.then(response => { + doSomething(response); +}) +.catch(e => { + returnError(e); +}) +.finally(() => { + runFinalCode(); +});</pre> + +<p>실제 예시는 <a href="https://mdn.github.io/learning-area/javascript/asynchronous/promises/promise-finally.html">promise-finally.html demo</a> 에 나와있습니다. (see the <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/promise-finally.html">source code</a> also). 이 예시는 위에서 만들어본 <code>Promise.all()</code> 데모와 똑같이 작동합니다. 다만 이번에는 <code>fetchAndDecode()</code> 함수에 다음 연쇄 작업으로 <code>finally()</code> 를 호출합니다.:</p> + +<pre class="brush: js notranslate">function fetchAndDecode(url, type) { + return fetch(url).then(response => { + if(type === 'blob') { + return response.blob(); + } else if(type === 'text') { + return response.text(); + } + }) + .catch(e => { + console.log(`There has been a problem with your fetch operation for resource "${url}": ` + e.message); + }) + .finally(() => { + console.log(`fetch attempt for "${url}" finished.`); + }); +}</pre> + +<p>이 로그는 각 fetch시도가 완료되면 콘솔에 메시지를 출력하여 사용자에게 알려줍니다.</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: <code>then()</code>/<code>catch()</code>/<code>finally()</code> is the async equivalent to <code>try</code>/<code>catch</code>/<code>finally</code> in sync code.</p> +</div> + +<h2 id="Building_your_own_custom_promises">Building your own custom promises</h2> + +<p>여기까지 오느라 수고하셨습니다. 여기까지 오면서 우리는 Promise를 직접 만들어봤습니다. 여러 개의 Promise를 <code>.then()</code> 을 사용하여 체이닝 하거나 사용자 정의함수를 조합하여, 비동기 Promise기반 함수를 만들었습니다. 이전에 만든 <code>fetchAndDecode()</code> 함수가 이를 잘 보여주고있죠.</p> + +<p>다양한 Promise 기반 API를 결합하여 사용자 정의 함수를 만드는 것은, Promise와 함께 원하는 기능을 만드는 가장 일반적인 방법이며, 대부분 모던 API는 이와 같은 원리를 기반으로 만들어지고 있습니다. 그리고 또 다른 방법이 있습니다.</p> + +<h3 id="Using_the_Promise_constructor">Using the Promise() constructor</h3> + +<p><code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promise()</a></code> constructor를 사용하여 사용자 정의 Promise를 만들 수 있습니다. 주로 Promise기반이 아닌 구식 비동기 API코드를 Promise기반 코드로 만들고 싶을 경우 사용합니다. 이 방법은 구식 프로젝트 코드, 라이브러리, 혹은 프레임워크를 지금의 Promise 코드와 함께 사용할 때 유용합니다.</p> + +<p>간단한 예를 들어 살펴보겠습니다. — 여기 Promise와 함께 사용되는 <code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout">setTimeout()</a></code> 호출이 있습니다. — 이 함수는 2초 후에 "Success!"라는 문자열과 함께 resolve됩니다. (통과된 <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve">resolve()</a></code> 호출에 의해);</p> + +<pre class="brush: js notranslate">let timeoutPromise = new Promise((resolve, reject) => { + setTimeout(function(){ + resolve('Success!'); + }, 2000); +});</pre> + +<p><code>resolve()</code> 와<code>reject()</code> 는 Promise의 fulful / reject일때의 일을 수행하기 위해 호출한 함수입니다. 이번의 경우 Promise는 "Success!"문자와 함께 fulfill 됐습니다.</p> + +<p>따라서 이 Promise를 호출할 때, 그 끝에 <code>.then()</code> 블럭을 사용하면 "Success!" 문자열이 전달될 것입니다. 아래 코드는 간단한 alert메시지를 출력하는 방법 입니다. :</p> + +<pre class="brush: js notranslate">timeoutPromise +.then((message) => { + alert(message); +})</pre> + +<p>혹은 아래처럼 쓸 수 있죠</p> + +<pre class="brush: js notranslate">timeoutPromise.then(alert); +</pre> + +<p>Try <a href="https://mdn.github.io/learning-area/javascript/asynchronous/promises/custom-promise.html">running this live</a> to see the result (also see the <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/custom-promise.html">source code</a>).</p> + +<p>위의 예시는 유연하게 적용된 예시가 아닙니다. — Promise는 항산 하나의 문자열로만 fulfil됩니다. 그리고 <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/reject">reject()</a></code> 조건도 정의되어있지 않습니다. (사실, <code>setTimeout()</code> 은 실패 조건이 필요없습니다, 그러니 이 예제에서는 없어도 됩니다.).</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: Why <code>resolve()</code>, and not <code>fulfill()</code>? The answer we'll give you, for now, is <em>it's complicated</em>.</p> +</div> + +<h3 id="Rejecting_a_custom_promise">Rejecting a custom promise</h3> + +<p><code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/reject">reject()</a></code> 메서드를 사용하여 Promise가 reject상태일 때 전달할 값을 지정할 수 있습니다. — <code>resolve()</code>와 똑같습니다. 여기엔 하나의 값만 들어갈 수 있습니다. Promise가 reject 되면 에러는 <code>.catch()</code> 블럭으로 전달됩니다.</p> + +<p>이전 예시를 좀 더 확장하여 <code>reject()</code> 을 추가하고, Promise가 fulfil일 때 다른 메시지도 전달할 수 있게 만들어봅시다.</p> + +<p>이전 예시 <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/custom-promise.html">previous example</a>를 복사한 후 이미 있는 <code>timeoutPromise()</code> 함수를 아래처럼 정의해주세요. :</p> + +<pre class="brush: js notranslate">function timeoutPromise(message, interval) { + return new Promise((resolve, reject) => { + if (message === '' || typeof message !== 'string') { + reject('Message is empty or not a string'); + } else if (interval < 0 || typeof interval !== 'number') { + reject('Interval is negative or not a number'); + } else { + setTimeout(function(){ + resolve(message); + }, interval); + } + }); +};</pre> + +<p>함수를 살펴보면 두 가지 매개변수가 있습니다. — 출력할 메시지와(<font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">message</span></font>) 메시지를 출력할 때 까지 기다릴 시간(<code>interval</code>)입니다. 맨 위에 <code>Promise</code> 오브젝트를 반환하도록 되어있습니다. 따라서 함수를 실행하면 우리가 사용하고 싶은 Promise가 반환될 것 입니다..</p> + +<p>Promise constructor 안에는 몇가지 사항을 확인하기 위해 <code>if ... else</code> 구문이 있습니다. :</p> + +<ol> + <li>첫번째로 메시지의 유효성을 검사합니다. 메시지가 비어있거나 문자가 아닌 경우, 에러 메시지와 함께 Promise를 reject합니다.</li> + <li>그 다음으로 interval의 유효성을 검사합니다. 숫자가 아니거나 음수일 경우, 에러 메시지와 함께 Promise를 reject합니다.</li> + <li>마지막은 항목은, 두 매개변수를 확인하여 유효할 경우 <code>setTimeout()</code>함수에 지정된 interval에 맞춰 Promise를 resolve합니다.</li> +</ol> + +<p><code>timeoutPromise()</code> 함수는 <code>Promise</code>를 반환하므로, <code>.then()</code>, <code>.catch()</code>, 기타등등 을 사용해 Promise 체이닝을 만들 수 있습니다. 아래와 같이 작성해봅시다. — 기존에 있는 <code>timeoutPromise</code> 를 삭제하고 아래처럼 바꿔주세요. :</p> + +<pre class="brush: js notranslate">timeoutPromise('Hello there!', 1000) +.then(message => { + alert(message); +}) +.catch(e => { + console.log('Error: ' + e); +});</pre> + +<p>이 코드를 저장하고 브라우저를 새로 고침하면 1초 후에 'Hello there!' alert가 출력될 것 입니다. 이제 메시지 내용을 비우거나 interval을 음수로 지정해보세요 그렇게 하면 Promise가 reject되며 에러 메시지를 콘솔에 출력해 줄 것입니다. 또한 resolved 메시지를 다르게 만들어 줄 수도 있습니다.</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: You can find our version of this example on GitHub as <a href="https://mdn.github.io/learning-area/javascript/asynchronous/promises/custom-promise2.html">custom-promise2.html</a> (see also the <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/promises/custom-promise2.html">source code</a>).</p> +</div> + +<h3 id="A_more_real-world_example">A more real-world example</h3> + +<p>위의 예제는 개념을 이해하기 쉽게 단순하게 만들었지만, 실제로 그다지 비동기적이지는 않습니다. 억지로 비동기적 작업을 구현하기 위해 <code>setTimeout()</code>을 사용하여 함수를 만들었지만 사용자 정의 Promise를 만들고 에러를 다루기엔 충분한 예제였습니다.</p> + +<p>좀 더 공부해볼 추가내용을 소개해주고 싶습니다. 바로 <a href="https://github.com/jakearchibald/idb/">Jake Archibald's idb library</a>입니다 이 라이브러리는 <code>Promise()</code> constructor의 비동기작업 응용을 보여주는 유용한 라이브러리 입니다. 클라이언트측에서 데이터를 저장하고 검색하기 위한 구식 callback 기반 API로 Promise와 함께 사용하는 <a href="/en-US/docs/Web/API/IndexedDB_API">IndexedDB API</a>입니다. <a href="https://github.com/jakearchibald/idb/blob/master/lib/idb.js">main library file</a>을 살펴보면 우리가 지금까지 다뤄본것과 같은 종류의 테크닉을 볼 수 있습니다. 아래 코드 블록은 basic request model이 Promise를 사용하게끔 변환해 주는 IndexedDB 메서드 입니다. :</p> + +<pre class="brush: js notranslate">function promisifyRequest(request) { + return new Promise(function(resolve, reject) { + request.onsuccess = function() { + resolve(request.result); + }; + + request.onerror = function() { + reject(request.error); + }; + }); +}</pre> + +<p>우리가 했던것 처럼 적절한 타이밍에 Promise를 fulfil하고 reject하는 이벤트 핸들러를 두 개 추가했습니다. :</p> + +<ul> + <li><code><a href="/en-US/docs/Web/API/IDBRequest">request</a></code>의 <a href="/en-US/docs/Web/API/IDBRequest/success_event"><code>success</code> event</a>가 실행될 때, <code><a href="/en-US/docs/Web/API/IDBRequest/onsuccess">onsuccess</a></code> 핸들러에 의해 fulfill된 Promise의 request <code><a href="/en-US/docs/Web/API/IDBRequest/result">result</a></code>를 반환한다.</li> + <li>반면 <code><a href="/en-US/docs/Web/API/IDBRequest">request</a></code>'s <a href="/en-US/docs/Web/API/IDBRequest/error_event"><code>error</code> event</a>가 실행되면 <code><a href="/en-US/docs/Web/API/IDBRequest/onerror">onerror</a></code> 핸들러에 의해 reject된 Promise의 request <code><a href="/en-US/docs/Web/API/IDBRequest/error">error</a></code>를 반환한다.</li> +</ul> + +<h2 id="Conclusion">Conclusion</h2> + +<p>Promises are a good way to build asynchronous applications when we don’t know the return value of a function or how long it will take to return. They make it easier to express and reason about sequences of asynchronous operations without deeply nested callbacks, and they support a style of error handling that is similar to the synchronous <code>try...catch</code> statement.</p> + +<p>Promises work in the latest versions of all modern browsers; the only place where promise support will be a problem is in Opera Mini and IE11 and earlier versions.</p> + +<p>We didn't touch on all promise features in this article, just the most interesting and useful ones. As you start to learn more about promises, you'll come across further features and techniques.</p> + +<p>Most modern Web APIs are promise-based, so you'll need to understand promises to get the most out of them. Among those APIs are <a href="/en-US/docs/Web/API/WebRTC_API">WebRTC</a>, <a href="/en-US/docs/Web/API/Web_Audio_API">Web Audio API</a>, <a href="/en-US/docs/Web/API/Media_Streams_API">Media Capture and Streams</a>, and many more. Promises will be more and more important as time goes on, so learning to use and understand them is an important step in learning modern JavaScript.</p> + +<h2 id="See_also">See also</h2> + +<ul> + <li><code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promise()</a></code></li> + <li><a href="/en-US/docs/Web/JavaScript/Guide/Using_promises">Using promises</a></li> + <li><a href="https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html">We have a problem with promises</a> by Nolan Lawson</li> +</ul> + +<p>{{PreviousMenuNext("Learn/JavaScript/Asynchronous/Timeouts_and_intervals", "Learn/JavaScript/Asynchronous/Async_await", "Learn/JavaScript/Asynchronous")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Concepts">General asynchronous programming concepts</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Introducing">Introducing asynchronous JavaScript</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Timeouts_and_intervals">Cooperative asynchronous JavaScript: Timeouts and intervals</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Promises">Graceful asynchronous programming with Promises</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Async_await">Making asynchronous programming easier with async and await</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Choosing_the_right_approach">Choosing the right approach</a></li> +</ul> diff --git a/files/ko/learn/javascript/asynchronous/timeouts_and_intervals/index.html b/files/ko/learn/javascript/asynchronous/timeouts_and_intervals/index.html new file mode 100644 index 0000000000..1f3d4f2a6a --- /dev/null +++ b/files/ko/learn/javascript/asynchronous/timeouts_and_intervals/index.html @@ -0,0 +1,598 @@ +--- +title: 'Cooperative asynchronous JavaScript: Timeouts and intervals' +slug: Learn/JavaScript/Asynchronous/Timeouts_and_intervals +translation_of: Learn/JavaScript/Asynchronous/Timeouts_and_intervals +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Asynchronous/Introducing", "Learn/JavaScript/Asynchronous/Promises", "Learn/JavaScript/Asynchronous")}}</div> + +<p class="summary">이 장에서는 자바스크립트가 설정된 시간이 경과하거나 혹은 정해진 시간 간격(예 : 초당 설정된 횟수)으로 비동기 코드를 작동하는 전형적인 방법을 살펴본다. 그리고 이 방법들이 어떤 것에 유용한지 얘기해 보고, 그 본질적인 문제에 대해 살펴본다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Prerequisites:</th> + <td>Basic computer literacy, a reasonable understanding of JavaScript fundamentals.</td> + </tr> + <tr> + <th scope="row">Objective:</th> + <td>To understand asynchronous loops and intervals and what they are useful for.</td> + </tr> + </tbody> +</table> + +<h2 id="Introduction">Introduction</h2> + +<p>오랜 시간 동안 웹플랫폼은 자바스크립트 프로그래머가 일정한 시간이 흐른 뒤에 비동기적 코드를 실행할 수 있게하는 다양한 함수들을 제공해 왔다. 그리고 프로그래머가 중지시킬 때까지 코드 블록을 반복적으로 실행하기 위한 다음과 같은 함수들이 있다.</p> + +<dl> + <dt><code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout">setTimeout()</a></code></dt> + <dd>특정 시간이 경과한 뒤에 특정 코드블록을 한번 실행한다.</dd> + <dt></dt> + <dt><code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setInterval">setInterval()</a></code></dt> + <dd>각각의 호출 간에 일정한 시간 간격으로 특정 코드블록을 반복적으로 실행한다.</dd> + <dt><code><a href="/en-US/docs/Web/API/window/requestAnimationFrame">requestAnimationFrame()</a></code></dt> + <dd>setInterval()의 최신 버전; 그 코드가 실행되는 환경에 관계없이 적절한 프레임 속도로 애니메이션을 실행시키면서, 브라우저가 다음 화면을 보여주기 전에 특정 코드블록을 실행한다.</dd> +</dl> + +<p>이 함수들에 의해 설정된 비동기 코드는 메인 스레드에서 작동한다. 그러나 프로세서가 이러한 작업을 얼마나 많이 수행하는지에 따라, 코드가 반복되는 중간에 다른 코드를 어느 정도 효율적으로 실행할 수 있다. 어쨌든 이러한 함수들은 웹사이트나 응용 프로그램에서 일정한 애니메이션 및 기타 배경 처리를 실행하는 데 사용된다. 다음 섹션에서는 그것들을 어떻게 사용할 수 있는지 보여줄 것이다.</p> + +<h2 id="setTimeout">setTimeout()</h2> + +<p>앞에서 언급했듯이 setTimeout ()은 지정된 시간이 경과 한 후 특정 코드 블록을 한 번 실행한다. 그리고 다음과 같은 파라미터가 필요하다.:</p> + +<ul> + <li>실행할 함수 또는 다른 곳에 정의 된 함수 참조.</li> + <li>코드를 실행하기 전에 대기 할 밀리세컨드 단위의 시간 간격 (1000밀리세컨드는 1 초)을 나타내는 숫자. 값을 0으로 지정하면(혹은 이 값을 모두 생략하면) 함수가 즉시 실행된다. 왜 이 파라미터를 수행해야 하는지도 좀 더살펴 볼 것이다. </li> + <li>함수가 실행될 때 함수에 전달해야할 파라미터를 나타내는 0이상의 값.</li> +</ul> + +<div class="blockIndicator note"> +<p><strong>Note:</strong> 타임아웃 콜백은 단독으로 실행되지 않기 때문에 지정된 시간이 지난 그 시점에 정확히 콜백 될 것이라는 보장은 없다. 그보다는 최소한 그 정도의 시간이 지난 후에 호출된다. 메인 스레드가 실행해야 할 핸들러를 찾기 위해 이런 핸들러들을 살펴보는 시점에 도달할 때까지 타임아웃 핸들러를 실행할 수 없다.</p> +</div> + +<p>아래 예제에서 브라우저는 2분이 지나면 익명의 함수를 실행하고 경보 메시지를 띄울 것이다. (<a href="https://mdn.github.io/learning-area/javascript/asynchronous/loops-and-intervals/simple-settimeout.html">see it running live</a>, and <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/loops-and-intervals/simple-settimeout.html">see the source code</a>):</p> + +<pre class="brush: js">let myGreeting = setTimeout(function() { + alert('Hello, Mr. Universe!'); +}, 2000)</pre> + +<p>지정한 함수가 꼭 익명일 필요는 없다. 함수에 이름을 부여 할 수 있고, 다른 곳에서 함수를 정의하고 setTimeout ()에 참조(reference)를 전달할 수도 있다. 아래 코드는 위의 코드와 같은 실행 결과를 얻을 수 있다. </p> + +<pre class="brush: js">// With a named function +let myGreeting = setTimeout(function sayHi() { + alert('Hello, Mr. Universe!'); +}, 2000) + +// With a function defined separately +function sayHi() { + alert('Hello Mr. Universe!'); +} + +let myGreeting = setTimeout(sayHi, 2000);</pre> + +<p>예를 들자면 timeout 함수와 이벤트에 의해 중복 호출되는 함수를 사용하려면 이 방법이 유용할 수 있다. 이 방법은 코드라인을 깔끔하게 정리하는 데 도움을 준다. 특히 timeout 콜백의 코드라인이 여러 줄이라면 더욱 그렇다. </p> + +<p>setTimeout ()은 나중에 타임아웃을 할 경우에 타임아웃을 참조하는데 사용하는 식별자 값을 리턴한다. 그 방법을 알아 보려면 아래{{anch("Clearing timeouts")}}을 참조하세요.</p> + +<h3 id="setTimeout_함수에_매개변수parameter_전달">setTimeout () 함수에 매개변수(parameter) 전달</h3> + +<p>setTimeout () 내에서 실행되는 함수에 전달하려는 모든 매개변수는 setTimeout () 매개변수 목록 끝에 추가하여 전달해야 한다. 아래 예제처럼, 이전 함수를 리팩터링하여 전달된 매개변수의 사람 이름이 추가된 문장을 표시할 수 있다.</p> + +<pre class="brush: js">function sayHi(who) { + alert('Hello ' + who + '!'); +}</pre> + +<p>Say hello의 대상이 되는 사람이름은 <code>setTimeout()의 세번째 매개변수로 함수에 전달된다.</code></p> + +<pre class="brush: js">let myGreeting = setTimeout(sayHi, 2000, 'Mr. Universe');</pre> + +<h3 id="timeout_취소">timeout 취소</h3> + +<p>마지막으로 타임아웃이 생성되면(setTimeout()이 실행되면) 특정시간이 경과하기 전에 <code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/clearTimeout">clearTimeout()</a></code>을 호출하여 타임아웃을 취소할 수 있다. <code><a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/clearTimeout">clearTimeout()</a></code>은 <code>setTimeout()</code>콜의 식별자를 매개변수로 <code>setTimeout()</code>에 전달한다. 위 예제의 타임아웃을 취소하려면 아래와 같이 하면 된다.</p> + +<pre class="brush: js">clearTimeout(myGreeting);</pre> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: 인사를 할 사람의 이름을 설정하고 별도의 버튼을 사용하여 인사말을 취소 할 수있는 약간 더 복잡한 폼양식 예제인 <a href="https://mdn.github.io/learning-area/javascript/asynchronous/loops-and-intervals/greeter-app.html">greeter-app.html</a> 을 참조하세요.</p> +</div> + +<h2 id="setInterval">setInterval()</h2> + +<p>setTimeout ()은 일정 시간이 지난 후 코드를 한 번 실행해야 할 때 완벽하게 작동합니다. 그러나 애니메이션의 경우와 같이 코드를 반복해서 실행해야 할 경우 어떨까요?</p> + +<p>이럴 경우에 setInterval ()이 필요합니다. setInterval ()은 setTimeout ()과 매우 유사한 방식으로 작동합니다. 다만 setTimeout ()처럼 첫 번째 매개 변수(함수)가 타임아웃 후에 한번 실행되는게 아니라 두 번째 매개 변수에 주어진 시간까지 반복적으로 실행되는 것이 차이점입니다. setInterval() 호출의 후속 파라미터로 실행 중인 함수에 필요한 파라미터를 전달할 수도 있다.</p> + +<p>예를 들어 봅시다. 다음 함수는 새 Date() 객체를 생성한 후에 ToLocaleTimeString()을 사용하여 시간데이터를 문자열로 추출한 다음 UI에 표시합니다. 그리고 setInterval()을 사용하여 초당 한 번 함수(displayTime)를 실행하면 초당 한 번 업데이트되는 디지털 시계와 같은 효과를 만들어냅니다.(<a href="https://mdn.github.io/learning-area/javascript/asynchronous/loops-and-intervals/setinterval-clock.html">see this live</a>, and also <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/loops-and-intervals/setinterval-clock.html">see the source</a>): </p> + +<pre class="brush: js">function displayTime() { + let date = new Date(); + let time = date.toLocaleTimeString(); + document.getElementById('demo').textContent = time; +} + +const createClock = setInterval(displayTime, 1000);</pre> + +<p>setTimeout()과 같이 setInterval()도 식별자 값을 리턴하여 나중에 interval을 취소해야 할 때 사용한다.</p> + +<h3 id="interval_취소">interval 취소</h3> + +<p>setInterval ()은 아무 조치를 취하지 않으면 끊임없이 계속 실행됩니다. 이 상태를 중지하는 방법이 필요합니다. 그렇지 않으면 브라우저가 추가 작업을 완료 할 수 없거나, 현재 처리 중인 애니메이션이 완료되었을 때 오류가 발생할 수 있습니다. setTimeout()과 같은 방식으로 setInterval () 호출에 의해 반환 된 식별자를 clearInterval () 함수에 전달하여 이 작업을 취소할수 있습니다.</p> + +<pre class="brush: js">const myInterval = setInterval(myFunction, 2000); + +clearInterval(myInterval);</pre> + +<h4 id="능동학습_자신만의_스톱워치를_만들기.">능동학습 : 자신만의 스톱워치를 만들기.</h4> + +<p>위에서 모두 설명해 드렸으니, 과제를 드리겠습니다. <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/loops-and-intervals/setinterval-clock.html">setInterval-clock.html</a> 예제를 수정하여 자신만의 간단한 스톱워치를 만들어 보세요.</p> + +<p>위에서 설명(디지털 시계)한 것처럼 시간을 표시해야 하고, 이 예제에서는 아래 기능을 추가하세요.</p> + +<ul> + <li>스톱워치를 실행시키는 "Start" 버튼. </li> + <li>일시정지나 종료시키는 "Stop" 버튼.</li> + <li>시간을 0으로 설정하는 "Reset" 버튼.</li> + <li>실제 시간을 표시하지 말고 경과된 시간을 초단위로 표시..</li> +</ul> + +<p>몇가지 힌트를 드립니다.</p> + +<ul> + <li>버튼 마크업은 여러분이 원하는 대로 구성하고 스타일링 하세요. 자바스크립트 버튼 레퍼런스를 가져올 수 있는 후크를 포함한 semantic HTML을 사용하세요.</li> + <li> 0에서 시작하여 상수 루프를 이용하여 1 초 단위로 증가하는 변수를 작성해 보세요.</li> + <li>앞서 설명한 Date () 객체를 사용하지 않고 이 예제를 작성하는 것이 더 쉽지만 정확도는 떨어집니다. 정확히 1000ms 후에 콜백이 시작된다고 보장 할 수는 없기 때문입니다. 보다 정확한 방법은 startTime = Date.now ()를 실행하여 사용자가 시작 버튼을 클릭했을 때 정확한 timestamp을 얻은 다음 Date.now ()-startTime을 실행하여 시간(milliseconds)을 얻어 냅니다.</li> + <li>시, 분, 초 단위의 시간을 별도의 변수를 통해 계산한 다음 각 루프 반복 후에 문자열로 함께 표시해 보세요. 두 번째 카운터에서 하나씩 해결할 수 있습니다.</li> + <li>어떻게 계산할 것인지 생각해 봅시다. + <ul> + <li>1시간은 3600초 입니다.</li> + <li>분단위 시간은 시간을 60으로 나눈 값에서 시간단위를 제거한 값입니다. 그리고 초단위 시간은 그 값에서 분단위 시간을 제거한 값입니다(예 :3700초를 60초로 나누면 3600초(시단위) + 100초(분단위), 분단위를 다시 60으로 나누면 60초(분단위) + 40초(초단위))</li> + </ul> + </li> + <li>시간값이 10밀리세컨드이하면 화면의 시간을 0으로 표시하세요. 더 일반적인 시계처럼 보일 겁니다.</li> + <li>스톱워치를 정지시키기 위해 interval을 취소해 보세요. 스톱워치를 리셋하기 위해 시간 카운터를 0으로 설정하고, interval을 취소한 후에 화면을 즉시 업데이트 하세요.</li> + <li>스타트 버튼이 클릭되면 버튼을 즉시 비활성화 시키고 스톱/리셋버튼이 클릭되면 다시 활성화해 보세요. 그렇지 않고 스타트 버튼이 여러번 클릭되면 setInterval()이 중복 실행되어서 실행 오류가 발생할 수 있습니다.</li> +</ul> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: If you get stuck, you can <a href="https://mdn.github.io/learning-area/javascript/asynchronous/loops-and-intervals/setinterval-stopwatch.html">find our version here</a> (see the <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/loops-and-intervals/setinterval-stopwatch.html">source code</a> also).</p> +</div> + +<h2 id="setTimeout과_setInterval에서_주의해야할_것_들">setTimeout()과 setInterval()에서 주의해야할 것 들</h2> + +<p>setTimeout()과 setInterval()에는 몇가지 주의해야 할 것들이 있습니다. 어떤 것인지 한번 살펴보겠습니다.</p> + +<h3 id="순환_timeouts">순환 timeouts</h3> + +<p>setTimeout()을 사용하는 또 다른 방법입니다. 바로 setInterval()을 사용하는 대신 setTimeout()을 이용해 같은코드를 반복적으로 실행시키는 방법입니다.</p> + +<p>The below example uses a recursive <code>setTimeout()</code> to run the passed function every 100 milliseconds: 아래 예제에서는 setTimeout()이 주어진 함수를 100밀리세컨드마다 실행합니다.</p> + +<pre class="brush: js">let i = 1; + +setTimeout(function run() { + console.log(i); + i++; + setTimeout(run, 100); +}, 100);</pre> + +<p>위 예제를 아래 예제와 비교해 보세요. 아래 예제는 setInterval()을 사용하여 같은 결과를 얻을 수 있습니다.</p> + +<pre class="brush: js">let i = 1; + +setInterval(function run() { + console.log(i); + i++ +}, 100);</pre> + +<h4 id="그렇다면_순환_setTimeout과_setInterval은_어떻게_다를까요">그렇다면 순환 setTimeout()과 setInterval()은 어떻게 다를까요?</h4> + +<p>두 방법의 차이는 미묘합니다.</p> + +<ul> + <li>순환 setTimeout ()은 실행과 실행 사이에 동일한 지연을 보장합니다. 위의 경우 100ms입니다. 코드가 실행 된 후 다시 실행되기 전에 100 ms 동안 대기하므로 간격은 코드 실행 시간에 관계없이 동일합니다.</li> + <li>setInterval ()을 사용하는 예제는 약간 다르게 작동합니다. 설정된 간격에는 실행하려는 코드를 실행하는 데 걸리는 시간이 포함됩니다. 코드를 실행하는 데 40ms가 걸리다면 간격이 60ms에 불과합니다.</li> + <li>setTimeout ()을 재귀적으로 사용할 때 각 반복은 다음 반복을 실행하기 전에 또 하나의 대기시간을 설정합니다. 즉, setTimeout ()의 두 번째 매개 변수의 값은 코드를 다시 실행하기 전에 대기 할 또 하나의 시간을 지정합니다.</li> +</ul> + +<p>코드가 지정한 시간 간격보다 실행 시간이 오래 걸리면 순환 setTimeout ()을 사용하는 것이 좋습니다. 이렇게하면 코드 실행 시간에 관계없이 실행 간격이 일정하게 유지되어 오류가 발생하지 않습니다.</p> + +<h3 id="즉시_timeouts">즉시 timeouts</h3> + +<p>setTimeout()의 값으로 0을 사용하면 메인 코드 스레드가 실행된 후에 가능한 한 빨리 지정된 콜백 함수의 실행을 예약할 수 있다.</p> + +<p>예를 들어 아래 코드 (<a href="https://mdn.github.io/learning-area/javascript/asynchronous/loops-and-intervals/zero-settimeout.html">see it live</a>) 는 "Hello"가 포함된 alert를 출력 한 다음 첫 번째 경고에서 OK를 클릭하자마자 "World"가 포함된 alert를 출력합니다.</p> + +<pre class="brush: js">setTimeout(function() { + alert('World'); +}, 0); + +alert('Hello');</pre> + +<p>이것은 모든 메인 스레드의 실행이 완료되자마자 실행되도록 코드 블록을 설정하려는 경우 유용할 할 수 있습니다. 비동기 이벤트 루프에 배치하면 곧바로 실행될 겁니다.</p> + +<h3 id="clearTimeout_와_clearInterval의_취소기능">clearTimeout() 와 clearInterval()의 취소기능</h3> + +<p>clearTimeout ()과 clearInterval ()은 모두 동일한 entry를 사용하여 대상 메소드(setTimeout () 또는 setInterval ())을 취소합니다. 흥미롭게도 이는 setTimeout () 또는 setInterval ()을 지우는 데 clearTimeout ()과 clearInterval ()메소드 어느 것을 사용해도 무방합니다.</p> + +<p>그러나 일관성을 유지하려면 clearTimeout ()을 사용하여 setTimeout () 항목을 지우고 clearInterval ()을 사용하여 setInterval () 항목을 지우십시오. 혼란을 피하는 데 도움이됩니다.</p> + +<h2 id="requestAnimationFrame">requestAnimationFrame()</h2> + +<p>requestAnimationFrame ()은 브라우저에서 애니메이션을 효율적으로 실행하기 위해 만들어진 특수한 반복 함수입니다. 근본적으로 setInterval ()의 최신 버전입니다. 브라우저가 다음에 디스플레이를 다시 표시하기 전에 지정된 코드 블록을 실행하여 애니메이션이 실행되는 환경에 관계없이 적절한 프레임 속도로 실행될 수 있도록합니다.</p> + +<p>setInterval ()을 사용함에 있어 알려진 문제점을 개선하기위해 만들어졌습니다. 예를 들어 장치에 최적화 된 프레임 속도로 실행되지 않는 문제, 때로는 프레임을 빠뜨리는 문제, 탭이 활성 탭이 아니거나 애니메이션이 페이지를 벗어난 경우에도 계속 실행되는 문제 등등이다 . <a href="http://creativejs.com/resources/requestanimationframe/index.html">CreativeJS에서 이에 대해 자세히 알아보십시오.</a></p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: requestAnimationFrame() 사용에 관한 예제들은 이 코스의 여러곳에서 찾아볼 수 있습니다. <a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Drawing_graphics">Drawing graphics</a> 와 <a href="/en-US/docs/Learn/JavaScript/Objects/Object_building_practice">Object building practice</a> 의 예제를 찾아 보세요.</p> +</div> + +<p>이 메소드는 화면을 다시 표시하기 전에 호출 할 콜백을 인수로 사용합니다. 이것이 일반적인 패턴입니다. 아래는 사용예를 보여줍니다.</p> + +<pre class="brush: js">function draw() { + // Drawing code goes here + requestAnimationFrame(draw); +} + +draw();</pre> + +<p>그 발상은 애니메이션을 업데이트하는 함수 (예 : 스프라이트 이동, 스코어 업데이트, 데이터 새로 고침 등)를 정의한 후 그것을 호출하여 프로세스를 시작하는 것입니다. 함수 블록의 끝에서 매개 변수로 전달 된 함수 참조를 사용하여 requestAnimationFrame ()을 호출하면 브라우저가 다음 화면을 재표시할 때 함수를 다시 호출하도록 지시합니다. 그런 다음 requestAnimationFrame ()을 반복적으로 호출하므로 계속 실행되는 것입니다.</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: 어떤 간단한 DOM 애니메이션을 수행하려는 경우, <a href="/en-US/docs/Web/CSS/CSS_Animations">CSS Animations</a> 은 JavaScript가 아닌 브라우저의 내부 코드로 직접 계산되므로 속도가 더 빠릅니다. 그러나 더 복잡한 작업을 수행하고 DOM 내에서 직접 액세스 할 수 없는 객체(예 :<a href="/en-US/docs/Web/API/Canvas_API">2D Canvas API</a> or <a href="/en-US/docs/Web/API/WebGL_API">WebGL</a> objects)를 포함하는 경우 대부분의 경우 requestAnimationFrame ()이 더 나은 옵션입니다. </p> +</div> + +<h3 id="여러분의_애니메이션의_작동속도는_얼마나_빠른가요">여러분의 애니메이션의 작동속도는 얼마나 빠른가요?</h3> + +<p>부드러운 애니메이션을 구현은 직접적으로 프레임 속도에 달려 있으며, 프레임속도는 초당 프레임 (fps)으로 측정됩니다. 이 숫자가 높을수록 애니메이션이 더 매끄럽게 보입니다.</p> + +<p>일반적으로 화면 재생률는 60Hz이므로 웹 브라우저를 사용할 때 여러분이 설정할 수 있는 가장 빠른 프레임 속도는 초당 60 프레임 (FPS)입니다. 이 속도보다 빠르게 설정하면 과도한 연산이 실행되어 화면이 더듬거리고 띄엄띄엄 표시될 수 있다. 이런 현상을 프레임 손실 또는 쟁크라고 한다. </p> + +<p>재생률 60Hz의 모니터에 60FPS를 달성하려는 경우 각 프레임을 렌더링하기 위해 애니메이션 코드를 실행하려면 약 16.7ms(1000/60)가 필요합니다. 그러므로 각 애니메이션 루프를 통과 할 때마다 실행하려고 하는 코드의 양을 염두에 두어야합니다.</p> + +<p>requestAnimationFrame()은 불가능한 경우에도 가능한한 60FPS 값에 가까워 지려고 노력합니다. 실제로 복잡한 애니메이션을 느린 컴퓨터에서 실행하는 경우 프레임 속도가 떨어집니다. requestAnimationFrame ()은 항상 사용 가능한 것을 최대한 활용합니다.</p> + +<h3 id="requestAnimationFrame이_setInterval_setTimeout과_다른점은">requestAnimationFrame()이 setInterval(), setTimeout()과 다른점은?</h3> + +<p>requestAnimationFrame () 메소드가 이전에 살펴본 다른 메소드와 어떻게 다른지에 대해 조금 더 이야기하겠습니다. 위의 코드를 다시 살펴보면;</p> + +<pre class="brush: js">function draw() { + // Drawing code goes here + requestAnimationFrame(draw); +} + +draw();</pre> + +<p>setInterval()을 사용하여 위와 같은 작업을 하는 방법을 살펴봅시다.</p> + +<pre class="brush: js">function draw() { + // Drawing code goes here +} + +setInterval(draw, 17);</pre> + +<p>앞에서언급했듯이 requestAnimationFrame ()은 시간 간격을 지정하지 않습니다. requestAnimationFrame ()은 현재 상황에서 최대한 빠르고 원활하게 실행됩니다. 어떤 이유로 애니메이션이 화면에 표시되지 않으면 브라우저는 그 애니메이션을 실행하는 데 시간을 낭비하지 않습니다.</p> + +<p>반면에 setInterval ()은 특정 시간간격을 필요로 합니다. 1000 ms/60Hz 계산을 통해 최종값 16.6에 도달 한 후 반올림(17)했습니다. 이때 반올림하는 것이 좋습니다. 그 이유는 반내림(16)을하면 60fps보다 빠르게 애니메이션을 실행하려고 하게 되지만 애니메이션의 부드러움에 아무런 영향을 미치지 않기 때문입니다. 앞에서 언급했듯이 60Hz가 표준 재생률입니다.</p> + +<h3 id="timestamp를_포함하기">timestamp를 포함하기</h3> + +<p>requestAnimationFrame() 함수에 전달 된 실제 콜백에는 requestAnimationFrame()이 실행되기 시작한 이후의 시간을 나타내는 timestamp를 매개변수로 제공할 수 있습니다. 장치 속도에 관계없이 특정 시간과 일정한 속도로 작업을 수행할 수 있으므로 유용합니다. 사용하는 일반적인 패턴은 다음과 같습니다.</p> + +<pre class="brush: js">let startTime = null; + +function draw(timestamp) { + if(!startTime) { + startTime = timestamp; + } + + currentTime = timestamp - startTime; + + // Do something based on current time + + requestAnimationFrame(draw); +} + +draw();</pre> + +<h3 id="브라우저_지원">브라우저 지원</h3> + +<p>requestAnimationFrame()은 setInterval() / setTimeout()보다 좀 더 최신 브라우저에서 지원됩니다. 가장 흥미롭게도 Internet Explorer 10 이상에서 사용할 수 있습니다. 따라서 별도의 코드로 이전 버전의 IE를 지원해야할 필요가 없다면, requestAnimationFrame()을 사용하지 않을 이유가 없습니다.</p> + +<h3 id="간단한_예">간단한 예</h3> + +<p>지금까지 이론적으로는 충분히 살펴보았습니다. 그러면 직접 requestAnimationFrame() 예제를 작성해 봅시다. 우리는 간단한 "스피너 애니메이션"을 만들 것입니다. 여러분들이 앱 사용중 서버 과부하일 때 이것을 자주 보았을 겁니다.</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: 실제로는 CSS 애니메이션을 사용하여 이러한 종류의 간단한 애니메이션을 실행해야 합니다. 그러나 이러한 종류의 예제는 requestAnimationFrame() 사용법을 보여주는 데 매우 유용하며, 각 프레임에서 게임의 디스플레이를 업데이트하는 것과 같이 좀 더 복잡한 작업을 수행 할 때 이러한 종류의 기술을 사용하는 것이 좋습니다.</p> +</div> + +<ol> + <li> + <p>먼저 HTML 템플릿을 <a href="https://github.com/mdn/learning-area/blob/master/html/introduction-to-html/getting-started/index.html">여기</a>에서.가져옵니다.</p> + </li> + <li> + <p><body>안에 빈 <div> 요소를 삽입합니다. 그리고 ↻캐릭터를 그 안에 추가합니다. 이 예제에서 이 원형 화살표가 회전하게됩니다.</p> + </li> + <li> + <p>아래 CSS를 HTML 템플릿에 여러분이 원하는 방식으로 적용하세요. 이 CSS는 페이지 배경을 빨간색으로, <body>의 height를 html height의 100%로 설정합니다. 그리고 <div>를 수직, 수평으로 <body> 중앙에 위치 시킵니다.</p> + + <pre class="brush: css">html { + background-color: white; + height: 100%; +} + +body { + height: inherit; + background-color: red; + margin: 0; + display: flex; + justify-content: center; + align-items: center; +} + +div { + display: inline-block; + font-size: 10rem; +}</pre> + </li> + <li> + <p></body> 태크 위에 <script>를 추가하세요.</p> + </li> + <li> + <p><script> 안에 아래 자바스크립트 코드를 추가하세요. 여기에서 <div>의 참조를 상수로 저장하고, rotateCount 변수를 0으로 설정하고, 나중에 requestAnimationFrame()의 시작 시간을 저장할 startTime 변수를 null로 설정하고, 그리고 requestAnimationFrame() 콜의 참조를 저장할 초기화하지 않은 rAF 변수를 선언합니다.</p> + + <pre class="brush: js">const spinner = document.querySelector('div'); +let rotateCount = 0; +let startTime = null; +let rAF; +</pre> + </li> + <li> + <p>그 아래에 draw() 함수를 추가합니다. 이 함수는 timestamp 매개변수를 포함하는 애니메이션 코드 작성에 사용됩니다.</p> + + <pre class="brush: js">function draw(timestamp) { + +}</pre> + </li> + <li> + <p>draw() 함수안데 다음 코드를 추가합니다. if 조건문으로 startTime이 정의되지 않았다면 startTime을 정의합니다 (루프 반복의 첫번째에만 작동합니다). 그리고 스피너를 회전시키는 rotateCount 변수값을 설정합니다(현재 timestamp는 시작 timestamp를 3으로 나눈 것이라서 그리 빠르지 않습니다).</p> + + <pre class="brush: js"> if (!startTime) { + startTime = timestamp; + } + + rotateCount = (timestamp - startTime) / 3; +</pre> + </li> + <li> + <p>draw() 함수 안의 이전 코드 아래에 다음 블록을 추가합니다. 이렇게하면 rotateCount 값이 359보다 큰지 확인합니다 (예 : 360, 완전한 원). 그렇다면 값을 모듈러 360 (즉, 값을 360으로 나눌 때 남은 나머지)으로 설정하여 원 애니메이션이 합리적인 낮은 값으로 중단없이 계속 될 수 있습니다. 꼭 이렇게 해야되는 것은 아니지만 "128000도" 같은 값보다는 0~359 도의 값으로 작업하는 것이 더 쉽습니다.</p> + + <pre class="brush: js">if (rotateCount > 359) { + rotateCount %= 360; +}</pre> + </li> + <li>다음으로 아래 코드를 추가하세요. 실제 스피너를 회전시키는 코드입니다. + <pre class="brush: js">spinner.style.transform = 'rotate(' + rotateCount + 'deg)';</pre> + </li> + <li> + <p> draw() 함수 제일 아래에 다음 코드를 추가합니다. 이 코드는 모든 작업의 키 포인트입니다. draw() 함수를 매개변수로 가져오는 requestAnimationFrame() 콜을 저장하기 위해 앞에서 정의한 rAF 변수를 설정합니다. 이 코드는 애니메이션을 실행시키고, 가능한한 60fps에 근사하게 draw() 함수를 계속 실행합니다.</p> + + <pre class="brush: js">rAF = requestAnimationFrame(draw);</pre> + </li> +</ol> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: You can find this <a href="https://mdn.github.io/learning-area/javascript/asynchronous/loops-and-intervals/simple-raf-spinner.html">example live on GitHub</a> (see the <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/loops-and-intervals/simple-raf-spinner.html">source code</a> also).</p> +</div> + +<h3 id="requestAnimationFrame_call의_취소">requestAnimationFrame() call의 취소</h3> + +<p>cancelAnimationFrame() 메소드를 호출하여 requestAnimationFrame()을 취소할 수 있다. (접두어가 "clear"가 아니고 "cancel"임에 유의) requestAnimationFrame()에 의해서 리턴된 rAF 변수값을 전달받아 취소한다. </p> + +<pre class="brush: js">cancelAnimationFrame(rAF);</pre> + +<h3 id="Active_learning_Starting_and_stopping_our_spinner">Active learning: Starting and stopping our spinner</h3> + +<p>In this exercise, we'd like you to test out the <code>cancelAnimationFrame()</code> method by taking our previous example and updating it, adding an event listener to start and stop the spinner when the mouse is clicked anywhere on the page.</p> + +<p>Some hints:</p> + +<ul> + <li>A <code>click</code> event handler can be added to most elements, including the document <code><body></code>. It makes more sense to put it on the <code><body></code> element if you want to maximize the clickable area — the event bubbles up to its child elements.</li> + <li>You'll want to add a tracking variable to check whether the spinner is spinning or not, clearing the animation frame if it is, and calling it again if it isn't.</li> +</ul> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: Try this yourself first; if you get really stuck, check out of our <a href="https://mdn.github.io/learning-area/javascript/asynchronous/loops-and-intervals/start-and-stop-spinner.html">live example</a> and <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/loops-and-intervals/start-and-stop-spinner.html">source code</a>.</p> +</div> + +<h3 id="Throttling_a_requestAnimationFrame_animation">Throttling a requestAnimationFrame() animation</h3> + +<p>One limitation of <code>requestAnimationFrame()</code> is that you can't choose your frame rate. This isn't a problem most of the time, as generally you want your animation to run as smoothly as possible, but what about when you want to create an old school, 8-bit-style animation?</p> + +<p>This was a problem for example in the Monkey Island-inspired walking animation from our <a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Drawing_graphics">Drawing Graphics</a> article:</p> + +<p>{{EmbedGHLiveSample("learning-area/javascript/apis/drawing-graphics/loops_animation/7_canvas_walking_animation.html", '100%', 260)}}</p> + +<p>In this example we have to animate both the position of the character on the screen, and the sprite being shown. There are only 6 frames in the sprite's animation; if we showed a different sprite frame for every frame displayed on the screen by <code>requestAnimationFrame()</code>, Guybrush would move his limbs too fast and the animation would look ridiculous. We therefore throttled the rate at which the sprite cycles its frames using the following code:</p> + +<pre class="brush: js">if (posX % 13 === 0) { + if (sprite === 5) { + sprite = 0; + } else { + sprite++; + } +}</pre> + +<p>So we are only cycling a sprite once every 13 animation frames. OK, so it's actually about every 6.5 frames, as we update <code>posX</code> (character's position on the screen) by two each frame:</p> + +<pre class="brush: js">if(posX > width/2) { + newStartPos = -((width/2) + 102); + posX = Math.ceil(newStartPos / 13) * 13; + console.log(posX); +} else { + posX += 2; +}</pre> + +<p>This is the code that works out how to update the position in each animation frame.</p> + +<p>The method you use to throttle your animation will depend on your particular code. For example, in our spinner example we could make it appear to move slower by only increasing our <code>rotateCount</code> by one on each frame instead of two.</p> + +<h2 id="Active_learning_a_reaction_game">Active learning: a reaction game</h2> + +<p>For our final section of this article, we'll create a 2-player reaction game. Here we have two players, one of whom controls the game using the <kbd>A</kbd> key, and the other with the <kbd>L</kbd> key.</p> + +<p>When the <em>Start</em> button is pressed, a spinner like the one we saw earlier is displayed for a random amount of time between 5 and 10 seconds. After that time, a message will appear saying "PLAYERS GO!!" — once this happens, the first player to press their control button will win the game.</p> + +<p>{{EmbedGHLiveSample("learning-area/javascript/asynchronous/loops-and-intervals/reaction-game.html", '100%', 500)}}</p> + +<p>Let's work through this.</p> + +<ol> + <li> + <p>First of all, download the <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/loops-and-intervals/reaction-game-starter.html">starter file for the app</a> — this contains the finished HTML structure and CSS styling, giving us a game board that shows the two players' information (as seen above), but with the spinner and results paragraph displayed on top of one another. We just have to write the JavaScript code.</p> + </li> + <li> + <p>Inside the empty {{htmlelement("script")}} element on your page, start by adding the following lines of code that define some constants and variables we'll need in the rest of the code:</p> + + <pre class="brush: js">const spinner = document.querySelector('.spinner p'); +const spinnerContainer = document.querySelector('.spinner'); +let rotateCount = 0; +let startTime = null; +let rAF; +const btn = document.querySelector('button'); +const result = document.querySelector('.result');</pre> + + <p>In order, these are:</p> + + <ol> + <li>A reference to our spinner, so we can animate it.</li> + <li>A reference to the {{htmlelement("div")}} element that contains the spinner, used for showing and hiding it.</li> + <li>A rotate count — how much we want to show the spinner rotated on each frame of the animation.</li> + <li>A null start time — will be populated with a start time when the spinner starts spinning.</li> + <li>An uninitialized variable to later store the {{domxref("Window.requestAnimationFrame", "requestAnimationFrame()")}} call that animates the spinner.</li> + <li>A reference to the Start button.</li> + <li>A reference to the results paragraph.</li> + </ol> + </li> + <li> + <p>Next, below the previous lines of code, add the following function. This simply takes two numerical inputs and returns a random number between the two. We'll need this to generate a random timeout interval later on.</p> + + <pre class="brush: js">function random(min,max) { + var num = Math.floor(Math.random()*(max-min)) + min; + return num; +}</pre> + </li> + <li> + <p>Next add in the <code>draw()</code> function, which animates the spinner. This is very similar to the version seen in the simple spinner example we looked at earlier:</p> + + <pre class="brush: js">function draw(timestamp) { + if(!startTime) { + startTime = timestamp; + } + + rotateCount = (timestamp - startTime) / 3; + + if(rotateCount > 359) { + rotateCount %= 360; + } + + spinner.style.transform = 'rotate(' + rotateCount + 'deg)'; + rAF = requestAnimationFrame(draw); +}</pre> + </li> + <li> + <p>Now it is time to set up the initial state of the app when the page first loads. Add the following two lines, which simply hide the results paragraph and spinner container using <code>display: none;</code>.</p> + + <pre class="brush: js">result.style.display = 'none'; +spinnerContainer.style.display = 'none';</pre> + </li> + <li> + <p>We'll also define a <code>reset()</code> function, which sets the app back to the original state required to start the game again after it has been played. Add the following at the bottom of your code:</p> + + <pre class="brush: js">function reset() { + btn.style.display = 'block'; + result.textContent = ''; + result.style.display = 'none'; +}</pre> + </li> + <li> + <p>OK, enough preparation. Let's make the game playable! Add the following block to your code. The <code>start()</code> function calls <code>draw()</code> to start the spinner spinning and display it in the UI, hides the <em>Start</em> button so we can't mess up the game by starting it multiple times concurrently, and runs a <code>setTimeout()</code> call that runs a <code>setEndgame()</code> function after a random interval between 5 and 10 seconds has passed. We also add an event listener to our button to run the <code>start()</code> function when it is clicked.</p> + + <pre class="brush: js">btn.addEventListener('click', start); + +function start() { + draw(); + spinnerContainer.style.display = 'block'; + btn.style.display = 'none'; + setTimeout(setEndgame, random(5000,10000)); +}</pre> + + <div class="blockIndicator note"> + <p><strong>Note</strong>: You'll see that in this example we are calling <code>setTimeout()</code> without storing the return value (so not <code>let myTimeout = setTimeout(functionName, interval)</code>). This works and is fine, as long as you don't need to clear your interval/timeout at any point. If you do, you'll need to save the returned identifier.</p> + </div> + + <p>The net result of the previous code is that when the <em>Start</em> button is pressed, the spinner is shown and the players are made to wait a random amount of time before they are then asked to press their button. This last part is handled by the <code>setEndgame()</code> function, which we should define next.</p> + </li> + <li> + <p>So add the following function to your code next:</p> + + <pre class="brush: js">function setEndgame() { + cancelAnimationFrame(rAF); + spinnerContainer.style.display = 'none'; + result.style.display = 'block'; + result.textContent = 'PLAYERS GO!!'; + + document.addEventListener('keydown', keyHandler); + + function keyHandler(e) { + console.log(e.key); + if(e.key === 'a') { + result.textContent = 'Player 1 won!!'; + } else if(e.key === 'l') { + result.textContent = 'Player 2 won!!'; + } + + document.removeEventListener('keydown', keyHandler); + setTimeout(reset, 5000); + }; +}</pre> + + <p>Stepping through this:</p> + + <ol> + <li>First we cancel the spinner animation with {{domxref("window.cancelAnimationFrame", "cancelAnimationFrame()")}} (it is always good to clean up unneeded processes), and hide the spinner container.</li> + <li>Next we display the results paragraph and set its text content to "PLAYERS GO!!" to signal to the players that they can now press their button to win.</li> + <li>We then attach a <code><a href="/en-US/docs/Web/API/Document/keydown_event">keydown</a></code> event listener to our document — when any button is pressed down, the <code>keyHandler()</code> function is run.</li> + <li>Inside <code>keyHandler()</code>, we include the event object as a parameter (represented by <code>e</code>) — its {{domxref("KeyboardEvent.key", "key")}} property contains the key that was just pressed, and we can use this to respond to specific key presses with specific actions.</li> + <li>We first log <code>e.key</code> to the console, which is a useful way of finding out the <code>key</code> value of different keys you are pressing.</li> + <li>When <code>e.key</code> is "a", we display a message to say that Player 1 won, and when <code>e.key</code> is "l", we display a message to say Player 2 won. Note that this will only work with lowercase a and l — if an uppercase A or L is submitted (the key plus <kbd>Shift</kbd>), it is counted as a different key.</li> + <li>Regardless of which one of the player control keys was pressed, we remove the <code>keydown</code> event listener using {{domxref("EventTarget.removeEventListener", "removeEventListener()")}} so that once the winning press has happened, no more keyboard input is possible to mess up the final game result. We also use <code>setTimeout()</code> to call <code>reset()</code> after 5 seconds — as we explained earlier, this function resets the game back to its original state so that a new game can be started.</li> + </ol> + </li> +</ol> + +<p>That's it, you're all done.</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: If you get stuck, check out <a href="https://mdn.github.io/learning-area/javascript/asynchronous/loops-and-intervals/reaction-game.html">our version of the reaction game</a> (see the <a href="https://github.com/mdn/learning-area/blob/master/javascript/asynchronous/loops-and-intervals/reaction-game.html">source code</a> also).</p> +</div> + +<h2 id="Conclusion">Conclusion</h2> + +<p>So that's it — all the essentials of async loops and intervals covered in one article. You'll find these methods useful in a lot of situations, but take care not to overuse them — since these still run on the main thread, heavy and intensive callbacks (especially those that manipulate the DOM) can really slow down a page if you're not careful.</p> + +<p>{{PreviousMenuNext("Learn/JavaScript/Asynchronous/Introducing", "Learn/JavaScript/Asynchronous/Promises", "Learn/JavaScript/Asynchronous")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Concepts">General asynchronous programming concepts</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Introducing">Introducing asynchronous JavaScript</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Timeouts_and_intervals">Cooperative asynchronous JavaScript: Timeouts and intervals</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Promises">Graceful asynchronous programming with Promises</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Async_await">Making asynchronous programming easier with async and await</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Asynchronous/Choosing_the_right_approach">Choosing the right approach</a></li> +</ul> diff --git a/files/ko/learn/javascript/building_blocks/build_your_own_function/index.html b/files/ko/learn/javascript/building_blocks/build_your_own_function/index.html new file mode 100644 index 0000000000..e700eb083d --- /dev/null +++ b/files/ko/learn/javascript/building_blocks/build_your_own_function/index.html @@ -0,0 +1,251 @@ +--- +title: Build your own function +slug: Learn/JavaScript/Building_blocks/Build_your_own_function +translation_of: Learn/JavaScript/Building_blocks/Build_your_own_function +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Functions","Learn/JavaScript/Building_blocks/Return_values", "Learn/JavaScript/Building_blocks")}}</div> + +<p class="summary">이번 장에선 앞의 글에서 배운 function이론을 사용하여 사용자 정의 함수를 만들어 봅니다. 사용자 정의 함수 연습과 더불어, 함수를 다루는 몇 가지 유용한 사항들도 설명을 하겠습니다. </p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">알아야 할 것:</th> + <td>기본적인 컴퓨터 사용 능력, HTML과 CSS에 대한 기본적인 이해, 자바스크립트 첫걸음, 함수 - 재사용 가능한 블록 코드</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>사용자 정의 함수를 만드는 방법에 대한 몇가지 예제 제공, 그와 관련된 여러가지 유용한 세부 사항 설명. </td> + </tr> + </tbody> +</table> + +<h2 id="Active_learning_Lets_build_a_function">Active learning: Let's build a function</h2> + +<p>여기서 만들 사용자 정의 함수는 <code>displayMessage()</code>라고 명명하겠습니다. 이 함수는 내장함수 <a href="/en-US/docs/Web/API/Window/alert">alert()</a> 을 사용하여 메시지를 표시하는 대신 다른 방법으로 페이지에 메시지 박스를 만듭니다. 이전에도 봐온 기능이지만 다시한번 연습해보자는 의미로 브라우저의 JavaScript 콘솔에 아래처럼 입력하세요 :</p> + +<pre class="brush: js notranslate">alert('This is a message');</pre> + +<p><code>alert</code> 함수는 하나의 인수만 사용합니다. — 전달받는 인수는 브라우저의 alert박스에 표시됩니다. 인수를 다른 문자로 교체하여 시험해보세요.</p> + +<p><code>alert</code> 함수는 제한적 입니다. : 원하는 메시지를 출력할 순 있지만 글자 색, 아이콘 등 다른 요소는 첨부할 수 없습니다. 아래서 다른 방법을 사용하여 재미있는 무언가를 만드는 방법을 소개하겠습니다.</p> + +<div class="note"> +<p><strong>Note</strong>: 이 예제는 모든 모던 브라우저에서 잘 작동합니다. 하지만 조금 오래된 브라우저는 스타일이 이상하게 적용될 수 있습니다. 이번 예제를 원활하게 즐기려면 Firefox, Opera, Chrome 브라우저를 사용해주세요</p> +</div> + +<h2 id="The_basic_function">The basic function</h2> + +<p>본격적으로 시작하기 앞서, 기본적인 함수를 만들어봅시다..</p> + +<div class="note"> +<p><strong>Note</strong>: 함수 명명규칙은 <a href="/en-US/Learn/JavaScript/First_steps/Variables#An_aside_on_variable_naming_rules">변수 명명규칙</a>과 동일하게 사용하는것이 좋습니다. 명명규칙이 동일해서 헷갈리지 않습니다. — 함수는 이름 뒤에 ()괄호가 함께 쓰이지만 변수는 그렇지 않습니다.</p> +</div> + +<ol> + <li><a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/functions/function-start.html">function-start.html</a> 파일을 연습하고있는 컴퓨터에 복사하여 저장합니다. HTML 구조는 매우 간단합니다. — body 태그에는 한 개의 버튼이 있습니다. 그리고 style 태그에 메시지 박스를 위한 CSS 블럭이 있습니다. 그리고 비어있는 {{htmlelement("script")}} 엘리먼트에 연습할 자바스크립트 코드를 앞으로 쓰겠씁니다..</li> + <li>다음으로 아래의 코드를 <code><script></code> 엘리먼트에 써봅시다. : + <pre class="brush: js notranslate">function displayMessage() { + +}</pre> + <code>function</code>이라는 키워드로 블럭 작성을 시작했습니다. 이 의미는 방금 우리가 함수를 정의했다는 뜻 입니다. 그리고 뒤에는 만들고자 하는 이름을 정의했고, 괄호에 이어 중괄호를 넣었습니다. 함수에 전달하고자 하는 인수는 괄호()안에 작성합니다. 그리고 우리가 만들고자 하는 로직은 중괄호 안에 작성합니다..</li> + <li>마지막으로 아래의 코드를 중괄호 안에 작성합니다.: + <pre class="brush: js notranslate">const html = document.querySelector('html'); + +const panel = document.createElement('div'); +panel.setAttribute('class', 'msgBox'); +html.appendChild(panel); + +const msg = document.createElement('p'); +msg.textContent = 'This is a message box'; +panel.appendChild(msg); + +const closeBtn = document.createElement('button'); +closeBtn.textContent = 'x'; +panel.appendChild(closeBtn); + +closeBtn.onclick = function() { + panel.parentNode.removeChild(panel); +}</pre> + </li> +</ol> + +<p>코드가 꽤 긴 편이니 조금씩 설명을 이어가겠습니다..</p> + +<p>첫 번째 줄에서 {{domxref("document.querySelector()")}} 라는 DOM API를 사용했습니다. 이 API는 {{htmlelement("html")}} 엘리먼트를 선택하여 <code>html</code>이라는 변수에 저장합니다. 따라서 아래와 같은 작업을 수행할 수 있습니다. :</p> + +<pre class="brush: js notranslate">const html = document.querySelector('html');</pre> + +<p>다음 줄에선 마찬가지로 DOM API인 {{domxref("document.createElement()")}} 을 사용하여 {{htmlelement("div")}} 엘리먼트를 생성한 후 <code>panel</code>변수에 저장합니다. 이 엘리먼트는 메시지 상자 바깥쪽 컨테이너가 될 것 입니다.</p> + +<p>그리고 또 다른 DOM API인 {{domxref("Element.setAttribute()")}} 을 사용하여 <code>class</code> 속성을 만들고 그 이름을 <code>msgBox</code>로 지정했습니다. 이 작업으로 스타일을 좀 더 쉽게 적용할 수 있습니다. — HTML 파일의 CSS 블럭을 살펴보면 <code>.msgBox</code> 클래스 셀렉터를 사용하여 메시지 박스와 그 내용을 스타일링할 수 있음을 알 수 있습니다.</p> + +<p>마지막으로, {{domxref("Node.appendChild()")}} DOM 함수를 사용하여 <code>html</code> 변수 안의 엘리먼트에 <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">panel</span></font> 변수에 저장된 <code><div></code>엘리먼트를 자식 엘리먼트로 삽입했습니다. 변수 선언만으로는 페이지에 표시할 수 없습니다. 반드시 아래처럼 작성하여 엘리먼트가 어디에 표시되는지 명시할 필요가 있습니다. </p> + +<pre class="brush: js notranslate">const panel = document.createElement('div'); +panel.setAttribute('class', 'msgBox'); +html.appendChild(panel);</pre> + +<p>다음 두 섹션은 위에서 봤던것과 동일한 <code>createElement()</code> 그리고 <code>appendChild()</code> 함수를 사용합니다. — {{htmlelement("p")}} 그리고 {{htmlelement("button")}} — 만들어 <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">panel</span></font>의 <code><div></code>태그의 자식 엘리먼트로 넣습니다. 우리는 {{domxref("Node.textContent")}} 속성을 사용하여 버튼에 x 라는 글자를 새겨넣습니다. 이 버튼은 사용자가 메시지 박스를 닫기를 원할 때 클릭/활성화 해야 하는 버튼입니다..</p> + +<pre class="brush: js notranslate">const msg = document.createElement('p'); +msg.textContent = 'This is a message box'; +panel.appendChild(msg); + +const closeBtn = document.createElement('button'); +closeBtn.textContent = 'x'; +panel.appendChild(closeBtn);</pre> + +<p>마지막으로 {{domxref("GlobalEventHandlers.onclick")}} 이벤트 핸들러를 사용하여 사용자가 x버튼을 클릭하면 메시지상자를 닫을 수 있게 만듭니다. </p> + +<p>간단히 말하면 <code>onclick</code> 핸들러는 버튼 (또는 실제 페이지의 다른 엘리먼트) 에서 사용할 수 있으며 버튼이 클릭됐을때 실행될 코드를 작성할 수 있습니다. 더 자세한 기능은 <a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events">events article</a>을 참조하세요. 이제 <code>onclick</code> 핸들러를 익명 함수와 동일하게 만들고, 그 안에 버튼이 클릭됐을 때 실행될 코드를 작성합니다. 함수 안쪽에서 {{domxref("Node.removeChild()")}} DOM API 함수를 사용하여 HTML 엘리먼트를 삭제하도록 명령합니다. — 이 경우 <code>panel</code> 변수의 <code><div></code>입니다.</p> + +<pre class="brush: js notranslate">closeBtn.onclick = function() { + panel.parentNode.removeChild(panel); +}</pre> + +<p>기본적으로 전체 코드 블럭은 아래처럼 보이는 HTML 블록을 생성하고 페이지에 나타내줍니다. :</p> + +<pre class="brush: html notranslate"><div class="msgBox"> + <p>This is a message box</p> + <button>x</button> +</div></pre> + +<p>많은 코드를 살펴봤습니다. — 예제에 포함된 CSS코드를 포함한 모든 코드를 지금 당장 이해할 필요는 없습니다. 이 예제에서 중점적으로 다루고자 하는 부분은 함수의 구조와 사용 방법 이었습니다. CSS 코드는 학습자의 흥미를 유도하기 위해 재미있는 것을 보여주고자 만들었습니다.</p> + +<h2 id="Calling_the_function">Calling the function</h2> + +<p>You've now got your function definition written into your <code><script></code> element just fine, but it will do nothing as it stands.</p> + +<ol> + <li>Try including the following line below your function to call it: + <pre class="brush: js notranslate">displayMessage();</pre> + This line invokes the function, making it run immediately. When you save your code and reload it in the browser, you'll see the little message box appear immediately, only once. We are only calling it once, after all.</li> + <li> + <p>Now open your browser developer tools on the example page, go to the JavaScript console and type the line again there, you'll see it appear again! So this is fun — we now have a reusable function that we can call any time we like.</p> + + <p>But we probably want it to appear in response to user and system actions. In a real application, such a message box would probably be called in response to new data being available, or an error having occurred, or the user trying to delete their profile ("are you sure about this?"), or the user adding a new contact and the operation completing successfully, etc.</p> + + <p>In this demo, we'll get the message box to appear when the user clicks the button.</p> + </li> + <li>Delete the previous line you added.</li> + <li>Next, we'll select the button and store a reference to it in a constant. Add the following line to your code, above the function definition: + <pre class="brush: js notranslate">const btn = document.querySelector('button');</pre> + </li> + <li>Finally, add the following line below the previous one: + <pre class="brush: js notranslate">btn.onclick = displayMessage;</pre> + In a similar way to our <code>closeBtn.onclick...</code> line inside the function, here we are calling some code in response to a button being clicked. But in this case, instead of calling an anonymous function containing some code, we are calling our function name directly.</li> + <li>Try saving and refreshing the page — now you should see the message box appear when you click the button.</li> +</ol> + +<p>You might be wondering why we haven't included the parentheses after the function name. This is because we don't want to call the function immediately — only after the button has been clicked. If you try changing the line to</p> + +<pre class="brush: js notranslate">btn.onclick = displayMessage();</pre> + +<p>and saving and reloading, you'll see that the message box appears without the button being clicked! The parentheses in this context are sometimes called the "function invocation operator". You only use them when you want to run the function immediately in the current scope. In the same respect, the code inside the anonymous function is not run immediately, as it is inside the function scope.</p> + +<p>If you tried the last experiment, make sure to undo the last change before carrying on.</p> + +<h2 id="Improving_the_function_with_parameters">Improving the function with parameters</h2> + +<p>As it stands, the function is still not very useful — we don't want to just show the same default message every time. Let's improve our function by adding some parameters, allowing us to call it with some different options.</p> + +<ol> + <li>First of all, update the first line of the function: + <pre class="brush: js notranslate">function displayMessage() {</pre> + + <div>to this:</div> + + <pre class="brush: js notranslate">function displayMessage(msgText, msgType) {</pre> + Now when we call the function, we can provide two variable values inside the parentheses to specify the message to display in the message box, and the type of message it is.</li> + <li>To make use of the first parameter, update the following line inside your function: + <pre class="brush: js notranslate">msg.textContent = 'This is a message box';</pre> + + <div>to</div> + + <pre class="brush: js notranslate">msg.textContent = msgText;</pre> + </li> + <li>Last but not least, you now need to update your function call to include some updated message text. Change the following line: + <pre class="brush: js notranslate">btn.onclick = displayMessage;</pre> + + <div>to this block:</div> + + <pre class="brush: js notranslate">btn.onclick = function() { + displayMessage('Woo, this is a different message!'); +};</pre> + If we want to specify parameters inside parentheses for the function we are calling, then we can't call it directly — we need to put it inside an anonymous function so that it isn't in the immediate scope and therefore isn't called immediately. Now it will not be called until the button is clicked.</li> + <li>Reload and try the code again and you'll see that it still works just fine, except that now you can also vary the message inside the parameter to get different messages displayed in the box!</li> +</ol> + +<h3 id="A_more_complex_parameter">A more complex parameter</h3> + +<p>On to the next parameter. This one is going to involve slightly more work — we are going to set it so that depending on what the <code>msgType</code> parameter is set to, the function will display a different icon and a different background color.</p> + +<ol> + <li>First of all, download the icons needed for this exercise (<a href="https://raw.githubusercontent.com/mdn/learning-area/master/javascript/building-blocks/functions/icons/warning.png">warning</a> and <a href="https://raw.githubusercontent.com/mdn/learning-area/master/javascript/building-blocks/functions/icons/chat.png">chat</a>) from GitHub. Save them in a new folder called <code>icons</code> in the same location as your HTML file. + + <div class="note"><strong>Note</strong>: The warning and chat icons were originally found on <a href="https://www.iconfinder.com/">iconfinder.com</a>, and designed by <a href="https://www.iconfinder.com/nazarr">Nazarrudin Ansyari</a> — Thanks! (The actual icon pages were since moved or removed.)</div> + </li> + <li>Next, find the CSS inside your HTML file. We'll make a few changes to make way for the icons. First, update the <code>.msgBox</code> width from: + <pre class="brush: css notranslate">width: 200px;</pre> + + <div>to</div> + + <pre class="brush: css notranslate">width: 242px;</pre> + </li> + <li>Next, add the following lines inside the <code>.msgBox p { ... }</code> rule: + <pre class="brush: css notranslate">padding-left: 82px; +background-position: 25px center; +background-repeat: no-repeat;</pre> + </li> + <li>Now we need to add code to our <code>displayMessage()</code> function to handle displaying the icons. Add the following block just above the closing curly brace (<code>}</code>) of your function: + <pre class="brush: js notranslate">if (msgType === 'warning') { + msg.style.backgroundImage = 'url(icons/warning.png)'; + panel.style.backgroundColor = 'red'; +} else if (msgType === 'chat') { + msg.style.backgroundImage = 'url(icons/chat.png)'; + panel.style.backgroundColor = 'aqua'; +} else { + msg.style.paddingLeft = '20px'; +}</pre> + Here, if the <code>msgType</code> parameter is set as <code>'warning'</code>, the warning icon is displayed and the panel's background color is set to red. If it is set to <code>'chat'</code>, the chat icon is displayed and the panel's background color is set to aqua blue. If the <code>msgType</code> parameter is not set at all (or to something different), then the <code>else { ... }</code> part of the code comes into play, and the paragraph is simply given default padding and no icon, with no background panel color set either. This provides a default state if no <code>msgType</code> parameter is provided, meaning that it is an optional parameter!</li> + <li>Let's test out our updated function, try updating the <code>displayMessage()</code> call from this: + <pre class="brush: js notranslate">displayMessage('Woo, this is a different message!');</pre> + + <div>to one of these:</div> + + <pre class="brush: js notranslate">displayMessage('Your inbox is almost full — delete some mails', 'warning'); +displayMessage('Brian: Hi there, how are you today?','chat');</pre> + You can see how useful our (now not so) little function is becoming.</li> +</ol> + +<div class="note"> +<p><strong>Note</strong>: If you have trouble getting the example to work, feel free to check your code against the <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/functions/function-stage-4.html">finished version on GitHub</a> (<a href="http://mdn.github.io/learning-area/javascript/building-blocks/functions/function-stage-4.html">see it running live</a> also), or ask us for help.</p> +</div> + +<h2 id="Test_your_skills!">Test your skills!</h2> + +<p>You've reached the end of this article, but can you remember the most important information? You can find some further tests to verify that you've retained this information before you move on — see <a href="/en-US/docs/Learn/JavaScript/Building_blocks/Test_your_skills:_Functions">Test your skills: Functions</a>. These tests require skills that are covered in the next article, so you might want to read those first before trying it.</p> + +<h2 id="Conclusion">Conclusion</h2> + +<p>Congratulations on reaching the end! This article took you through the entire process of building up a practical custom function, which with a bit more work could be transplanted into a real project. In the next article we'll wrap up functions by explaining another essential related concept — return values.</p> + +<ul> +</ul> + +<p>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Functions","Learn/JavaScript/Building_blocks/Return_values", "Learn/JavaScript/Building_blocks")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/conditionals">Making decisions in your code — conditionals</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Looping_code">Looping code</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions">Functions — reusable blocks of code</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Build_your_own_function">Build your own function</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Return_values">Function return values</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events">Introduction to events</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Image_gallery">Image gallery</a></li> +</ul> diff --git a/files/ko/learn/javascript/building_blocks/functions/index.html b/files/ko/learn/javascript/building_blocks/functions/index.html new file mode 100644 index 0000000000..4cc3420afe --- /dev/null +++ b/files/ko/learn/javascript/building_blocks/functions/index.html @@ -0,0 +1,394 @@ +--- +title: 함수 — 재사용 가능한 코드 블록 +slug: Learn/JavaScript/Building_blocks/Functions +translation_of: Learn/JavaScript/Building_blocks/Functions +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Looping_code","Learn/JavaScript/Building_blocks/Build_your_own_function", "Learn/JavaScript/Building_blocks")}}</div> + +<p class="summary">코딩에 있어서 또 하나의 중요한 개념은 바로 '함수'입니다. 함수란, 한 가지의 일을 수행하는 코드가 블럭으로 묶여있는 것을 말하며, 간단한 명령만으로 동일한 코드를 필요한 곳마다 반복해서 사용하지 않을 수 있게 만들어 줍니다. 이번 장에서는 함수에 대한 기본 문법과 파라미터(parameter) 및 범위(scope), 그리고 호출 방법에 대해 설명합니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">필요 사항:</th> + <td>기본적인 컴퓨터 활용 능력, HTML과 CSS의 기본적인 이해, <a href="/en-US/docs/Learn/JavaScript/First_steps">자바스크립트 첫 단계</a>.</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>JavaScript 함수의 기본 개념을 이해합니다.</td> + </tr> + </tbody> +</table> + +<h2 id="함수는_어디에서_찾을_수_있나요">함수는 어디에서 찾을 수 있나요?</h2> + +<p>자바스크립트 어디서든 함수를 찾을 수 있습니다. 사실, 우리는 지금까지 수업에서 함수를 계속 사용해왔습니다; 함수에 대해서 그렇게 말해오지 않았을 뿐이죠. 그러나 이제 함수에 대해서 분명하게 말하고, 실제로 문법을 탐험할 때가 되었습니다. </p> + +<p> <a href="/ko/docs/Learn/JavaScript/Building_blocks/Looping_code#%EB%A3%A8%ED%94%84%EC%9D%98_%ED%91%9C%EC%A4%80">for loop</a>, <a href="/ko/docs/Learn/JavaScript/Building_blocks/Looping_code#while_%EA%B7%B8%EB%A6%AC%EA%B3%A0_do_..._while">while 과 do...while loop</a>, 또는 <a href="/ko/docs/Learn/JavaScript/Building_blocks/%EC%A1%B0%EA%B1%B4%EB%AC%B8#if_..._else_%EB%AC%B8">if...else문</a>과 같은 일반적인 내장 언어 구조를 사용하지 <strong>않고</strong> — <code>()</code> —같은 괄호 쌍을 사용했다면 당신은 함수를 사용하고 있던 겁니다</p> + +<h2 id="브라우저_내장_함수">브라우저 내장 함수</h2> + +<p>우리는 이 코스에서 많은 브라우저 빌트인 함수를 사용해왔습니다.<br> + 예를 들어, 우리가 매번 텍스트 string을 조작할 때마다:</p> + +<pre class="brush: js notranslate">var myText = 'I am a string'; +var newString = myText.replace('string', 'sausage'); +console.log(newString); +// the replace() string function takes a string, +// replaces one substring with another, and returns +// a new string with the replacement made</pre> + +<p>또는 우리가 배열을 조작할 때마다:</p> + +<pre class="brush: js notranslate">var myArray = ['I', 'love', 'chocolate', 'frogs']; +var madeAString = myArray.join(' '); +console.log(madeAString); +// the join() function takes an array, joins +// all the array items together into a single +// string, and returns this new string</pre> + +<p>또는 우리가 무작위의 숫자를 생성할 때마다:</p> + +<pre class="brush: js notranslate">var myNumber = Math.random(); +// the random() function generates a random +// number between 0 and 1, and returns that +// number</pre> + +<p>...우리는 함수를 사용하고 있었어요!</p> + +<div class="note"> +<p><strong>Note</strong>: Feel free to enter these lines into your browser's JavaScript console to re-familiarize yourself with their functionality, if needed.</p> +</div> + +<p>JavaScript 언어는 당신 스스로 코드 전체를 적을 필요 없이, 유용한 것들을 할 수 있게 해주는 많은 내장 함수를 가지고 있습니다. 사실, 브라우저 내장 함수를 <strong>호출</strong>("함수를 실행하다"는 말을 멋있게 "호출하다"라고 하기도 합니다)할 때 호출하는 일부 코드는 JavaScript로 작성할 수 없었습니다 — 이러한 함수 중 상당수는 백그라운드 브라우저 코드의 일부를 호출하고 있으며, 이는 JavaScript와 같은 웹 언어가 아니라 C++와 같은 저수준 시스템 언어로 작성됩니다.</p> + +<p>명심하세요. 몇몇 브라우저 내장함수는 JavaScript core가 아닌 브라우저 API의 일부입니다. 브라우저 API는 기본 언어에서 더 많은 기능을 쓸 수 있게 만들어 졌습니다. (<a href="/ko/docs/Learn/JavaScript/First_steps/What_is_JavaScript#%EA%B7%B8%EB%9E%98%EC%84%9C_%EC%A7%84%EC%A7%9C_%EC%96%B4%EB%96%A4_%EC%9D%BC%EC%9D%84_%ED%95%A0_%EC%88%98_%EC%9E%88%EB%82%98%EC%9A%94">앞선 코스</a>에서 더 자세한 설명을 볼 수 있습니다). 브라우저 API를 다루는 법은 나중에 더 살펴보도록 하겠습니다.</p> + +<h2 id="함수_대_메소드">함수 대 메소드</h2> + +<p>우리가 다음으로 넘어가기 전에, 확실하게 짚고 가야할 게 있습니다. — 기술적으로, Built-in browser functions은 functions이 아닙니다. 그들은 <strong>methods</strong>죠. 이 문장이 약간 이상하고 혼란스럽게 들릴 수 있겠지만, 걱정마세요. — function과 method 이 두 단어는 광범위하게 교체가능하답니다. 최소한 그들의 용도적 측면과 지금 당신의 배움 단계에서는요.<br> + <br> + 구별되는 점은 methods는 objects안에 정의된 functions이라는 겁니다. Built-in browser functions(methods)와 변수(<strong>properties</strong>라 불리는 것들)는 코드를 더욱 효율적이고 다루기 쉽게하기 위해 구조화된 objects안에 저장되어 있습니다.</p> + +<p>당신은 아직 구조화된 JavaScript objects의 내부 동작에 대해서까지는 배우지 않아도 괜찮습니다. — 당신은 우리가 가르쳐 줄 objects의 내부 동작에 관한 모든 것인 모듈과, 어떻게 당신만의 모듈을 창조할 수 있는지에 대해 기다릴 수 있습니다. 현재로서는, 우리는 단지 어떤 혼동도 가능한 method 대 function(당신이 웹에서 이용가능한 관련 자원들을 볼때, 두 가지 용어를 만날 가능 성이 충분히 있는)에 대해 정리하고 싶을 뿐입니다. </p> + +<h2 id="사용자_정의_함수">사용자 정의 함수</h2> + +<p>또한 지금까지 많은 <strong>사용자 정의 함수</strong>(브라우저가 아닌 코드에 정의된 함수)를 봤습니다. 바로 뒤에 괄호가 있는 사용자가 정의한 이름을 볼 때마다, 바로 사용자 정의 함수를 사용하고 있었던 겁니다. <a href="/en-US/docs/Learn/JavaScript/Building_blocks/Looping_code">loops article</a>의 <a href="http://mdn.github.io/learning-area/javascript/building-blocks/loops/random-canvas-circles.html">random-canvas-circles.html</a> 예제(전체 <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/random-canvas-circles.html">소스 코드</a> 참조)에는 다음과 같은 <code>draw()</code> 사용자 정의 함수가 포함되어 있습니다:</p> + +<pre class="brush: js notranslate">function draw() { + ctx.clearRect(0,0,WIDTH,HEIGHT); + for (var i = 0; i < 100; i++) { + ctx.beginPath(); + ctx.fillStyle = 'rgba(255,0,0,0.5)'; + ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI); + ctx.fill(); + } +}</pre> + +<p>이 함수는 {{htmlelement("canvas")}} 요소 안에 100개의 임의의 원을 그립니다. 원할 때마다 아래 코드로 함수를 호출할 수 있습니다:</p> + +<pre class="brush: js notranslate">draw();</pre> + +<p>모든 코드를 또 작성하지 않고 말이죠. 그리고 함수는 당신이 원하는 코드를 포함할 수 있습니다. 심지어 함수 내의 다른 함수를 불러올 수도 있구요. 위의 예시는 아래와 같이 정의된 코드를 <code>random()</code> 을 통해 세번이나 호출하고 있죠.</p> + +<pre class="brush: js notranslate">function random(number) { + return Math.floor(Math.random()*number); +}</pre> + +<p><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random">Math.random()</a> 라는 내장함수는 오직 0과 1사이의 소수를 생성해내기 때문에 우리는 위의 함수가 필요했습니다. 우리는 0과 특정 수 사이의 무작위한 정수를 원했거든요.</p> + +<h2 id="함수_호출">함수 호출</h2> + +<p>지금까지 꽤 잘 따라온 거 같은데 혹시 모르니깐 말해 주자면... 정의된 함수를 작동시키기 위해선 함수를 '호출' 해야 돼요. 함수 호출은 함수의 이름을 괄호와 함께 코드 내에 적어 주면 됩니다.</p> + +<pre class="brush: js notranslate">function myFunction() { + alert('hello'); +} + +myFunction() +// calls the function once</pre> + +<h2 id="익명_함수">익명 함수</h2> + +<p>당신은 조금 다른 방식으로 정의되거나 호출되는 함수를 본 적 있을 거예요. 이제까지 우리는 이런 식으로 함수를 생성했죠: </p> + +<pre class="brush: js notranslate">function myFunction() { + alert('hello'); +}</pre> + +<p>하지만 이름 없는 함수 또한 만들 수 있답니다.</p> + +<pre class="brush: js notranslate">function() { + alert('hello'); +}</pre> + +<p>이건 <strong>익명 함수</strong>라고 불려요. 이름이 없다는 뜻이죠! 익명함수는 스스로 뭘 어쩌지 못 해요. 익명함수는 주로 이벤트 핸들러와 사용됩니다. 아래의 예시는 함수 내의 코드가 버튼을 클릭함에 따라 작동한다는 걸 보여주죠. </p> + +<pre class="brush: js notranslate">var myButton = document.querySelector('button'); + +myButton.onclick = function() { + alert('hello'); +}</pre> + +<p>위의 예시는 페이지 상의 클릭을 위해 {{htmlelement("button")}} 요소를 필요로 합니다. 당신은 코스를 거치며 이런 구조의 코드를 꽤 봐왔을 거예요. 다음 예시에서 더 많은 걸 배워 보자구요.</p> + +<p>당신은 변수 속에 익명함수를 넣을 수 있어요. 예시입니다.</p> + +<pre class="brush: js notranslate">var myGreeting = function() { + alert('hello'); +}</pre> + +<p>이 함수는 이런 식으로 호출되죠:</p> + +<pre class="brush: js notranslate">myGreeting();</pre> + +<p>이 방법은 효과적으로 함수에 이름을 부여하고 있어요. 당신은 다중 변수들에 함수를 할당할 수도 있죠. 예를 들면,</p> + +<pre class="brush: js notranslate">var anotherGreeting = function() { + alert('hello'); +}</pre> + +<p>이제 함수는 이런 식으로도 호출이 가능해졌구요.</p> + +<pre class="brush: js notranslate">myGreeting(); +anotherGreeting();</pre> + +<p>하지만 위의 방식은 사람 헷갈리게 만들어요. 그니깐 쓰진 맙시다! 함수를 만들 땐 아래의 형태를 고수하는 게 나아요.</p> + +<pre class="brush: js notranslate">function myGreeting() { + alert('hello'); +}</pre> + +<p>익명함수는 이벤트 발생에 따른 수많은 코드를 작동시키기 위해 주로 쓰이게 돼요. 이벤트 핸들러를 사용한 버튼의 클릭과 같은 상황에 말이죠. 자, 그 코드는 아래와 같이 생겼어요.</p> + +<pre class="brush: js notranslate">myButton.onclick = function() { + alert('hello'); + // 내가 원하는 만큼 얼마든지 + // 여기에 코드를 작성하면 됩니다! +}</pre> + +<h2 id="매개변수"><strong>매개변수</strong></h2> + +<p>몇몇 함수는 호출을 위해 매개변수를 필요로 하는 경우가 있습니다. 이런 함수가 제대로 작동하기 위해선 함수 괄호 안에 값들을 넣어주어야 해요.</p> + +<div class="note"> +<p><strong>Note</strong>: 매개변수는 종종 arguments, properties, 심지어 attributes 라고도 불려요.</p> +</div> + +<p>예를 들어, 내장 함수인 <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random">Math.random()</a>은 어떤 매개변수도 필요로 하지 않습니다. 이 함수는 호출되면 늘 0과 1사이의 무작위 수를 반환해 주죠. </p> + +<pre class="brush: js notranslate">var myNumber = Math.random();</pre> + +<p>하지만 내장 함수 <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace">replace()</a>는 두 개의 매개변수를 필요로 합니다. 대체될 문자와 대체할 문자죠. </p> + +<pre class="brush: js notranslate">var myText = 'I am a string'; +var newString = myText.replace('string', 'sausage');</pre> + +<div class="note"> +<p><strong>Note</strong>: 여러 개의 매개변수는 콤마에 의해 구분되어 집니다. </p> +</div> + +<p>매개변수는 이따금 선택 사항이기도 합니다. 당신이 명시해 줄 필요가 없다는 뜻이죠. 그런 경우, 일반적으로 함수는 디폴트 기능을 수행합니다. 예를 들어, 배열과 관련된 <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/join">join()</a> 함수의 매개변수가 그렇죠.</p> + +<pre class="brush: js notranslate">var myArray = ['I', 'love', 'chocolate', 'frogs']; +var madeAString = myArray.join(' '); +// returns 'I love chocolate frogs' +var madeAString = myArray.join(); +// returns 'I,love,chocolate,frogs'</pre> + +<p>만일 결합의 기준이 될 매개변수가 없다면, 콤마가 매개변수로서 사용됩니다.</p> + +<h2 id="함수_스코프와_충돌">함수 스코프와 충돌</h2> + +<p>우리 '스코프(scope)'에 대해 얘기해 볼까요? '스코프'는 함수와 관련된 매우 중요한 개념입니다. 함수를 생성할 때, 변수 및 함수 내 정의된 코드들은 그들만의 '스코프' 안에 자리하게 됩니다. 그 말인 즉슨, 다른 함수의 내부나 외부 함수의 코드가 접근할 수 없는 그들만의 구획에 갇혀 있다는 뜻입니다. </p> + +<p>함수 바깥에 선언된 가장 상위 레벨의 스코프를 '<strong>전역 스코프</strong>(global scope)' 라고 부릅니다.전역 스코프 내에 정의된 값들은 어느 코드든 접근이 가능합니다.</p> + +<p>자바스크립트는 다양한 이유로 인해 이와 같은 기능을 제공하지만, 주로는 안전성과 구조 때문입니다. 어떤 때에는 당신의 변수가 어느 코드나 접근 가능한 변수가 되는 걸 원치 않을 겁니다. 당신이 어딘가에서 불러온 외부 스크립트가 문제를 일으킬 수도 있으니깐요. 외부 스크립트의 코드와 같은 변수 이름을 사용하면 충돌이 일어나게 돼요. 이건 악의적일 수도 있고, 아님 뭐 단순한 우연이겠죠.</p> + +<p>예를 들어 , 당신에게 두 개의 외부 자바스크립트 파일을 호출하는 HTML이 있다고 쳐요. 그 둘은 같은 이름으로 정의된 변수와 함수를 사용하고 있습니다.</p> + +<pre class="brush: html notranslate"><!-- Excerpt from my HTML --> +<script src="first.js"></script> +<script src="second.js"></script> +<script> + greeting(); +</script></pre> + +<pre class="brush: js notranslate">// first.js +var name = 'Chris'; +function greeting() { + alert('Hello ' + name + ': welcome to our company.'); +}</pre> + +<pre class="brush: js notranslate">// second.js +var name = 'Zaptec'; +function greeting() { + alert('Our company is called ' + name + '.'); +}</pre> + +<p>두 함수 모두 <code>greeting()</code>라고 불리지만, 당신은 <code>second.js</code> 파일의 <code>greeting()</code> 함수에만 접근 가능합니다. HTML 소스 코드 상 후자이므로, 그 파일의 변수와 기능이 <code>first.js</code>것을 덮어쓰는 거죠.</p> + +<div class="note"> +<p><strong>Note</strong>: 예제를 여기서 볼 수 있습니다. <a href="http://mdn.github.io/learning-area/javascript/building-blocks/functions/conflict.html">running live on GitHub</a> (<a href="https://github.com/mdn/learning-area/tree/master/javascript/building-blocks/functions">source code</a> 또한 볼 수 있습니다.).</p> +</div> + +<p>함수의 일부를 코드 안에 가두는 것은 이러한 문제를 피할 수 있고, 가장 좋은 방법이라 여겨집니다.</p> + +<p>동물원 같네요. 사자, 얼룩말, 호랑이, 그리고 펭귄은 자신들만의 울타리 안에 있으며, 그들의 울타리 내부에 있는 것만 건드릴 수 있어요. 함수 스코프처럼 말이죠. 만약 동물들이 다른 울타리 안으로 들어갈 수 있었다면, 문제가 생겼을 겁니다. 좋게는 다른 동물이 낯선 거주 환경에서 불편함을 느끼는 정도겠죠. 사자나 호랑이가 펭귄의 물기 많고 추운 영역 안에서 끔찍함을 느끼듯이요. 하지만 최악의 상황엔 사자나 호랑이가 펭귄을 먹어 치울 지도 모르죠!</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14079/MDN-mozilla-zoo.png" style="display: block; margin: 0 auto;"></p> + +<p>사육사는 전역 스코프와 같습니다. 그들은 모든 울타리에 들어갈 수 있고, 먹이를 보충하고, 아픈 동물들을 돌볼 수 있어요.</p> + +<h3 id="실습_스코프랑_놀자">실습: 스코프랑 놀자</h3> + +<p>스코프 사용의 실례를 한번 봅시다.</p> + +<ol> + <li>먼저, 주어진 <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/functions/function-scope.html">function-scope.html</a> 예제의 복사본을 만드세요. 예제에는 2개의 function <code>a()</code> 와 <code>b()</code> 와, 3개의 변수 — <code>x</code>, <code>y</code>, 와 <code>z</code> —가 있습니다. 그 중 2개는 함수 안에 정의되어 있으며, 1개는 전역 범위에 정의되어 있습니다. It also contains a third function called <code>output()</code>, 이건 하나의 매개변수만 받으며, and outputs it in a paragraph on the page.</li> + <li>예제를 인터넷 브라우저나 텍스트 에디터를 통해 열어봅시다.</li> + <li>브라우저 개발자 툴을에서 자바스크립트 콘솔을 엽시다. 자바스크립트 콘솔에서 아래와 같이 작성해보세요: + <pre class="brush: js notranslate">output(x);</pre> + 변수 <code>x</code>의 결과값을 볼 수 있습니다.</li> + <li>Now try entering the following in your console + <pre class="brush: js notranslate">output(y); +output(z);</pre> + Both of these should return an error along the lines of "<a href="/en-US/docs/Web/JavaScript/Reference/Errors/Not_defined">ReferenceError: y is not defined</a>". Why is that? Because of function scope — <code>y</code> and <code>z</code> are locked inside the <code>a()</code> and <code>b()</code> functions, so <code>output()</code> can't access them when called from the global scope.</li> + <li>However, what about when it's called from inside another function? Try editing <code>a()</code> and <code>b()</code> so they look like this: + <pre class="brush: js notranslate">function a() { + var y = 2; + output(y); +} + +function b() { + var z = 3; + output(z); +}</pre> + Save the code and reload it in your browser, then try calling the <code>a()</code> and <code>b()</code> functions from the JavaScript console: + + <pre class="brush: js notranslate">a(); +b();</pre> + You should see the <code>y</code> and <code>z</code> values output in the page. This works fine, as the <code>output()</code> function is being called inside the other functions — in the same scope as the variables it is printing are defined in, in each case. <code>output()</code> itself is available from anywhere, as it is defined in the global scope.</li> + <li>Now try updating your code like this: + <pre class="brush: js notranslate">function a() { + var y = 2; + output(x); +} + +function b() { + var z = 3; + output(x); +}</pre> + </li> + <li>Save and reload again, and try this again in your JavaScript console: + <pre class="brush: js notranslate">a(); +b();</pre> + </li> + <li>Both the <code>a()</code> and <code>b()</code> call should output the value of x — 1. These work fine because even though the <code>output()</code> calls are not in the same scope as <code>x</code> is defined in, <code>x</code> is a global variable so is available inside all code, everywhere.</li> + <li>Finally, try updating your code like this: + <pre class="brush: js notranslate">function a() { + var y = 2; + output(z); +} + +function b() { + var z = 3; + output(y); +}</pre> + </li> + <li>Save and reload again, and try this again in your JavaScript console: + <pre class="brush: js notranslate">a(); +b();</pre> + This time the <code>a()</code> and <code>b()</code> calls will both return that annoying "<a href="/en-US/docs/Web/JavaScript/Reference/Errors/Not_defined">ReferenceError: z is not defined</a>" error — this is because the <code>output()</code> calls and the variables they are trying to print are not defined inside the same function scopes — the variables are effectively invisible to those function calls.</li> +</ol> + +<div class="note"> +<p><strong>Note</strong>: The same scoping rules do not apply to loop (e.g. <code>for() { ... }</code>) and conditional blocks (e.g. <code>if() { ... }</code>) — they look very similar, but they are not the same thing! Take care not to get these confused.</p> +</div> + +<div class="note"> +<p><strong>Note</strong>: The <a href="/en-US/docs/Web/JavaScript/Reference/Errors/Not_defined">ReferenceError: "x" is not defined</a> error is one of the most common you'll encounter. If you get this error and you are sure that you have defined the variable in question, check what scope it is in.</p> +</div> + +<ul> +</ul> + +<h3 id="Functions_inside_functions">Functions inside functions</h3> + +<p>Keep in mind that you can call a function from anywhere, even inside another function. This is often used as a way to keep code tidy — if you have a big complex function, it is easier to understand if you break it down into several sub-functions:</p> + +<pre class="brush: js notranslate">function myBigFunction() { + var myValue; + + subFunction1(); + subFunction2(); + subFunction3(); +} + +function subFunction1() { + console.log(myValue); +} + +function subFunction2() { + console.log(myValue); +} + +function subFunction3() { + console.log(myValue); +} +</pre> + +<p>Just make sure that the values being used inside the function are properly in scope. The example above would throw an error <code>ReferenceError: myValue is not defined</code>, because although the <code>myValue</code> variable is defined in the same scope as the function calls, it is not defined inside the function definitions — the actual code that is run when the functions are called. To make this work, you'd have to pass the value into the function as a parameter, like this:</p> + +<pre class="brush: js notranslate">function myBigFunction() { + var myValue = 1; + + subFunction1(myValue); + subFunction2(myValue); + subFunction3(myValue); +} + +function subFunction1(value) { + console.log(value); +} + +function subFunction2(value) { + console.log(value); +} + +function subFunction3(value) { + console.log(value); +}</pre> + +<h2 id="Conclusion">Conclusion</h2> + +<p>This article has explored the fundamental concepts behind functions, paving the way for the next one in which we get practical and take you through the steps to building up your own custom function.</p> + +<h2 id="See_also">See also</h2> + +<ul> + <li><a href="/en-US/docs/Web/JavaScript/Guide/Functions">Functions detailed guide</a> — covers some advanced features not included here.</li> + <li><a href="/en-US/docs/Web/JavaScript/Reference/Functions">Functions reference</a></li> + <li><a href="/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters">Default parameters</a>, <a href="/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions">Arrow functions</a> — advanced concept references</li> +</ul> + +<ul> +</ul> + +<p>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Looping_code","Learn/JavaScript/Building_blocks/Build_your_own_function", "Learn/JavaScript/Building_blocks")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/conditionals">Making decisions in your code — conditionals</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Looping_code">Looping code</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions">Functions — reusable blocks of code</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Build_your_own_function">Build your own function</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Return_values">Function return values</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events">Introduction to events</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Image_gallery">Image gallery</a></li> +</ul> diff --git a/files/ko/learn/javascript/building_blocks/index.html b/files/ko/learn/javascript/building_blocks/index.html new file mode 100644 index 0000000000..27e2a90cf5 --- /dev/null +++ b/files/ko/learn/javascript/building_blocks/index.html @@ -0,0 +1,49 @@ +--- +title: JavaScript 구성요소 +slug: Learn/JavaScript/Building_blocks +tags: + - 가이드 + - 국제화 + - 소개 + - 자바스크립트 + - 초보자 + - 함수 +translation_of: Learn/JavaScript/Building_blocks +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">이번 장에서는 조건문, 반복문, 함수, 이벤트 등 일반적으로 발생하는 코드 종류를 중심으로 JavaScript의 중요한 기본 기능에 대해 설명합니다. 지금까지의 과정을 지나면서 여기서 다룰 내용을 살짝 보셨겠지만 좀 더 심도있게 다루겠습니다.</p> + +<h2 id="선행사항">선행사항</h2> + +<p>시작하기전에, 기본 <a href="/ko/docs/Learn/HTML/Introduction_to_HTML">HTML</a>, <a href="/ko/docs/Learn/CSS/Introduction_to_CSS">CSS</a> 기본지식을 가지고 계신 것이 좋습니다. 그리고 <a href="/ko/docs/Learn/JavaScript/First_steps">JavaScript 첫 걸음</a>을 꼭 진행하신후 오시기 바랍니다.</p> + +<div class="note"> +<p><strong>Note</strong>: 여기 나온 코드를 작성하고 실행해 볼 수 없는 환경이라면 (태블릿, 스마트폰, 기타장치) , <a href="http://jsbin.com/">JSBin</a>이나 <a href="https://glitch.com">Glitch</a>에서 대부분의 예제를 시험해 볼 수 있습니다.</p> +</div> + +<h2 id="가이드">가이드</h2> + +<dl> + <dt><a href="/ko/docs/Learn/JavaScript/Building_blocks/conditionals">Making decisions in your code — conditionals</a></dt> + <dd>어떤 프로그래밍 언어든 코드는 의사 결정을 내리고 입력 내용에 따라 작업을 수행해야합니다. 예를 들어 게임에서 플레이어의 생명 수치가 0이면 게임이 종료됩니다. 날씨 앱에서는 아침에 해가 뜬 그림을 보여주고 밤에는 달과 별을 보여줍니다. 이 문서에서는 JavaScript에서 조건문이 작동하는 방법을 살펴 보겠습니다. </dd> + <dt><a href="/ko/docs/Learn/JavaScript/Building_blocks/Looping_code">반복문</a></dt> + <dd>때로는 여러 반복 작업을 수행해야 할 때가 있습니다. 예를 들면 이름 목록을 살펴보는 것입니다. 프로그래밍에서 이런 반복 작업은 매우 적합합니다. JavaScript의 반복문 구조를 살펴봅니다.</dd> + <dt><a href="/ko/docs/Learn/JavaScript/Building_blocks/Functions">함수 — 코드 재사용</a></dt> + <dd>코딩의 또 다른 핵심 개념은 <strong>함수</strong>입니다. <strong>함수</strong>를 사용하면 정의된 구간 안에 하나의 작업을 하는 코드를 저장한 후, 같은 코드를 여러 번 입력하지 않고도 짧은 명령어를 사용해 이 코드를 이용할 수 있습니다. 기본 문법, 함수, 범위 및 매개 변수를 호출하고 정의하는 방법과 같은 함수의 기본 개념을 살펴봅니다.</dd> + <dt><a href="/ko/docs/Learn/JavaScript/Building_blocks/Build_your_own_function">함수 만들기</a></dt> + <dd>그동안 배운 이론을 활용해 실제 코드를 작성해봅니다. 사용자 정의 함수를 작성해 보고, 함수의 유용한 기능을 좀 더 알아봅니다.</dd> + <dt><a href="/ko/docs/Learn/JavaScript/Building_blocks/Return_values">함수는 값을 반환한다</a></dt> + <dd>함수에 대해 알아야 할 마지막 필수 개념은 반환값입니다. 어떤 함수는 완료하면서 값을 반환하지 않지만, 반환하는 함수도 있습니다. 값이 무엇인지, 코드에서 어떻게 사용하는지, 여러분이 작성한 함수가 어떻게 값을 반환하는지 이해하는 것이 중요합니다.</dd> + <dt><a href="/ko/docs/Learn/JavaScript/Building_blocks/Events">Introduction to events</a></dt> + <dd>이벤트란 프로그래밍중인 시스템에서 발생하는 동작이나 발생을 말하며, 시스템에서 그에 대해 알려주므로 원하는 경우 사용자가 어떤 방식으로든 이에 응답 할 수 있습니다. 예를 들어 사용자가 웹 페이지에서 버튼을 클릭하면 정보 상자를 표시하여 해당 작업에 응답 할 수 있습니다. 이 마지막 문서에서는 이벤트를 둘러싼 몇 가지 중요한 개념에 대해 이야기하고 브라우저에서 어떻게 작동하는지 살펴 보겠습니다.</dd> +</dl> + +<h2 id="평가">평가</h2> + +<p>여기에선 위에서 다룬 JavaScript 기본 사항에 대해 여러분이 얼마나 이해했는지 테스트해볼 수 있습니다..</p> + +<dl> + <dt><a href="/ko/docs/Learn/JavaScript/Building_blocks/Image_gallery">Image gallery</a></dt> + <dd>이제 JavaScript의 기본 구성 요소를 살펴 보았으므로 많은 웹 사이트에서 볼 수있는 공통 항목인 JavaScript 기반 이미지 갤러리를 만들어 반복문, 함수, 조건문, 이벤트에 대한 지식을 테스트합니다.</dd> +</dl> diff --git a/files/ko/learn/javascript/building_blocks/looping_code/index.html b/files/ko/learn/javascript/building_blocks/looping_code/index.html new file mode 100644 index 0000000000..e95a78af37 --- /dev/null +++ b/files/ko/learn/javascript/building_blocks/looping_code/index.html @@ -0,0 +1,948 @@ +--- +title: Looping code +slug: Learn/JavaScript/Building_blocks/Looping_code +tags: + - for문 + - 반복문 + - 초보자 +translation_of: Learn/JavaScript/Building_blocks/Looping_code +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/조건문", "Learn/JavaScript/Building_blocks/Functions", "Learn/JavaScript/Building_blocks")}}</div> + +<p class="summary">프로그래밍 언어는 다양한 작업을 통해 반복적 인 작업을 신속하게 처리 할 수 있습니다. 이제 우리는 JavaScript를 사용하여 반복 구문을 사용하여 편리하게 처리 할 수 있습니다. </p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">선수 과목 :</th> + <td>기본적인 컴퓨터 활용 능력, HTML과 CSS, <a href="/en-US/docs/Learn/JavaScript/First_steps">자바 스크립트</a> 의 기본 이해 .</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>JavaScript에서 루프를 사용하는 방법을 이해합니다.</td> + </tr> + </tbody> +</table> + +<h2 id="나를_계속_붙잡아_라.">나를 계속 붙잡아 라.</h2> + +<p>반복(loop), 반복 반복. <a href="https://en.wikipedia.org/wiki/Froot_Loops">popular breakfast cereals</a>, <a href="https://en.wikipedia.org/wiki/Vertical_loop">roller coasters</a> 그리고 <a href="https://en.wikipedia.org/wiki/Loop_(music)">musical production</a>과 같이, 그것들은 프로그래밍의 중요한 개념이다. 프로그래밍 loop는 반복적으로 동일한 작업을 반복하는것이고 이런것들을 프로그래밍 언어로 loop라 한다.</p> + +<p>가족들이 일주일동안 먹을 식량이 충분한지 확신하기 위해 고민하는 농부의 상황을 보자. 그는 이것을 알기위해 다음과 같은 loop를 취할수 있다:</p> + +<p><br> + <img alt="" src="https://mdn.mozillademos.org/files/13755/loop_js-02-farm.png" style="display: block; margin: 0 auto;"></p> + +<p>이 loop에서 다음과 같이 우리는 한가지 이상의 기능을 가질수 있다:</p> + +<ul> + <li><strong>counter</strong>은 특정 값으로 초기화된다 — loop의 시작점이다. ("시작: I have no food", 위 그림을 참고).</li> + <li><strong>exit condition</strong>는 loop가 멈추는 기준이 되는 종료 조건 — 보통 counter가 특정 값에 도달하면 멈추게된다. 이것은 위에서 "Have I got enough food?"라고 설명되어 있다. 가족에게 먹일 음식 10개가 필요하다고 가정 해 보자.</li> + <li><strong>iterator</strong>는 끝나는 조건에 도달 할 때까지 일반적으로 counter를 각각의 연속된 루프에서 조금 씩 증가시킨다. 우리는 위에 명시적으로 설명하지 않았지만, 농부가 시간 당 음식을 2개씩 수집 할 수 있다고 생각할 수 있다. 매시간 후, 그가 모은 음식의 양은 2개씩 증가하고, 그는 음식이 충분한 지 여부를 확인한다. 그가 10개(종료 조건)에 도달하면, 그는 수집을 중지하고 집에 갈수 있다.</li> +</ul> + +<p>{{glossary("pseudocode")}}에서 이것은 다음과 같아 보일 것이다.:</p> + +<pre class="notranslate">loop(food = 0; foodNeeded = 10) { + if (food = foodNeeded) { + exit loop; + // We have enough food; let's go home + } else { + food += 2; // Spend an hour collecting 2 more food + // loop will then run again + } +}</pre> + +<p>따라서 필요한 음식의 양은 10으로 설하고, 현재 농부의 양은 0으로 설정한다. 매 반복마다 농부의 음식 양이 필요한 양과 같은지 확인한다. 필요한 양을 얻었다면 loop를 종료 할수 있다. 그렇지 않다면, 농부는 음식을 모을때까지 다시 반복해서 loop를 실행한다.</p> + +<h3 id="왜_귀찮게">왜 귀찮게?</h3> + +<p>여기에서 loop의 뒤에 있는 고급개념을 이해했을 것이다. 하지만 "그래 뭐 괜찮군 그래서 이 코드가 어떻게 도움이 될수 있는거지?"라고 생각할수도 있다. 앞서 말햇듯이 <strong>loop는 반복적인 작업을 빠르게 동일한 작업을 반복해서 수행해 완료하는 것이다.</strong></p> + +<p>종종 코드는 각각의 연속적인 반복된 loop에서 조금씩 달라질수도 있다. 그래서 유사하지만 약간 다른 작업에 이것을 이용해 작업을 완료할수도 있다.만약 너가 여러가지 다른종류의 계산을 해야한다면, 반복해서 처리하는게 아닌 각각 계산하고 싶을것이다.</p> + +<p>Loop가 왜 그렇게 좋은지 완벽하게 설명하는 예제를 한번 보자. {{htmlelement("canvas")}} element에 100개의 무작위 원을 그려야 한다고 가정해보자. (예제를 다시 실행하여 다른 임의의 세트를 보려면 Update 버튼을 클릭) :</p> + +<div class="hidden"> +<h6 id="Hidden_code">Hidden code</h6> + +<pre class="brush: html notranslate"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>Random canvas circles</title> + <style> + html { + width: 100%; + height: inherit; + background: #ddd; + } + + canvas { + display: block; + } + + body { + margin: 0; + } + + button { + position: absolute; + top: 5px; + left: 5px; + } + </style> + </head> + <body> + + <button>Update</button> + + <canvas></canvas> + + + <script> + const btn = document.querySelector('button'); + const canvas = document.querySelector('canvas'); + const ctx = canvas.getContext('2d'); + + let WIDTH = document.documentElement.clientWidth; + let HEIGHT = document.documentElement.clientHeight; + + canvas.width = WIDTH; + canvas.height = HEIGHT; + + function random(number) { + return Math.floor(Math.random()*number); + } + + function draw() { + ctx.clearRect(0,0,WIDTH,HEIGHT); + for (let i = 0; i < 100; i++) { + ctx.beginPath(); + ctx.fillStyle = 'rgba(255,0,0,0.5)'; + ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI); + ctx.fill(); + } + } + + btn.addEventListener('click',draw); + + </script> + + </body> +</html></pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_code', '100%', 400, "", "", "hide-codepen-jsfiddle") }}</p> + +<p>지금 당장은 모든 코드를 이해할 필요는 없지만 실제로100개의 원을 그리는 코드를 살펴보자:</p> + +<pre class="brush: js notranslate">for (let i = 0; i < 100; i++) { + ctx.beginPath(); + ctx.fillStyle = 'rgba(255,0,0,0.5)'; + ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI); + ctx.fill(); +}</pre> + +<ul> + <li>코드의 앞부분에서 정의한<code>random()</code>은 <code>0</code> 그리고 <code>x-1</code>사이의 정수를 반환한다.</li> + <li><code>WIDTH</code> 그리고 <code>HEIGHT</code> 는 내부 브라우저 윈도우의 너비와 높이이다.</li> +</ul> + +<p>우리는 이 코드를 100번 반복하기 위해서 loop를 사용하고 있다. 너는 여기에서 기본적인 아이디어를 얻을수 있다. 코드는 페이지에서 임의의 위치에 원을 그린다. 코드의 크기가 100개가 되든 1000개가 되든 또는 10,000개가 되든간에 동일하게 작업을 수행할것이다. 너는 숫자만 변경하면된다.</p> + +<p>만약 우리가 loop를 사용하지 않았다면 원을 그릴때마다 다음 코드를 반복해서 써야한다 :</p> + +<pre class="brush: js notranslate">ctx.beginPath(); +ctx.fillStyle = 'rgba(255,0,0,0.5)'; +ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI); +ctx.fill();</pre> + +<p>이것은 겁나 지루하고 빠르게 유지하기 힘들것이다. 이럴때 loop를 사용하는게가장 좋다.</p> + +<h2 id="루프의_표준">루프의 표준</h2> + +<p>특정 loop 구문을 살펴보도록 하자. 대부분의 시간을 보낼 첫번째는 for loop이다. 이 구문은 다음과 같다:</p> + +<pre class="notranslate">for (initializer; exit-condition; final-expression) { + // code to run +}</pre> + +<p>여기서 우리가 알수있는것:</p> + +<ol> + <li><code>for</code> 라는 키워드를 쓰고 그옆에 괄호를 만든다.</li> + <li>괄호 안에는 세미콜론(;)으로 구분 된 세개의 항목이 있다. + <ol> + <li><strong>initializer</strong> — 일반적으로 숫자로 설정된 변수이며 루프가 실행 된 횟수가 얼마나 되는제 되는지 알기위해 증가한다 그것을 <strong>counter variable</strong>라고 한다.</li> + <li><strong>exit-condition</strong> — 앞에서 언급했듯이 loop가 loop를 언제 멈출지 정의한다. 이 조건은 일반적으로 비교 연산자, 종료 조건이 충족되었는지 확인하는 테스트를 특징으로 하는 표현식이다.</li> + <li>A <strong>final-expression</strong> — 이것은 매번 loop 전체가 반복이 될때 항상 분석(또는 실행)한다. 일반적으로 <strong>counter variable</strong>를 증가(또는 경우에 따라 감소)하여 종료 조건 값으로 점점 가까워진다.</li> + </ol> + </li> + <li>코드 블럭을 감싸는 중괄호({}) — 중괄호 안에 있는 코드는 loop가 반복 될 때마다 실행된다.</li> +</ol> + +<p>실제 예제를 보면서 이러한 것들이 무엇을 더 확실하게 시각화 할 수 있는지 살펴보자.</p> + +<pre class="brush: js notranslate">const cats = ['Bill', 'Jeff', 'Pete', 'Biggles', 'Jasmin']; +let info = 'My cats are called '; +const para = document.querySelector('p'); + +for (let i = 0; i < cats.length; i++) { + info += cats[i] + ', '; +} + +para.textContent = info;</pre> + +<p>이것은 우리에게 다음과 같은 결과를 보여준다:</p> + +<div class="hidden"> +<h6 id="Hidden_code_2">Hidden code 2</h6> + +<pre class="brush: html notranslate"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>Basic for loop example</title> + <style> + + </style> + </head> + <body> + + <p></p> + + + <script> + const cats = ['Bill', 'Jeff', 'Pete', 'Biggles', 'Jasmin']; + let info = 'My cats are called '; + const para = document.querySelector('p'); + + for (let i = 0; i < cats.length; i++) { + info += cats[i] + ', '; + } + + para.textContent = info; + + </script> + + </body> +</html></pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_code_2', '100%', 60, "", "", "hide-codepen-jsfiddle") }}</p> + +<div class="note"> +<p><strong>Note</strong>: 너는 <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/basic-for.html">example code on GitHub</a> too (also <a href="http://mdn.github.io/learning-area/javascript/building-blocks/loops/basic-for.html">see it running live</a>)에서 예제를 찾을수 있다.</p> +</div> + +<p>이것은 배열의 항목을 반복하는 데 사용되는 loop를 보여 주며 각각의 항목을 사용하여 JavaScript에서 매우 일반적인 패턴을 나타낸다:</p> + +<ol> + <li>iterator <code>i</code>는 <code>0</code>에서부터 시작한다 (<code>let i = 0</code>).</li> + <li><code><font face="Arial, x-locale-body, sans-serif">cats의 배열의 길이보다 작을때 까지만 실행하라는 명령을 받았다. 이것은 중요하다. 종료 조건은 loop가 계속 실행되는 조건을 나타낸다. 따라서 이 경우에는 </font>i < cats.length</code> 까지만 loop가 true여서 계속 실행된다.</li> + <li>loop 안에서 현재 loop항목(<code>cats[i가 몇번 실행되었던지 간에</code> <code>cats[i]</code> 는)과 쉼표 및 공백을 <code>info</code>변수 끝에 위치한다: + <ol> + <li>처음 실행되는 동안, <code>i = 0</code>, 이므로 <code>cats[0] + ', '</code> 는 info ("Bill, ")에 옆에 위치한다.</li> + <li>두번째로 실행되는 동안, <code>i = 1</code>, 이므로 <code>cats[1] + ', '</code> 역시 info ("Jeff, ")에 옆에 위치한다.</li> + <li>계속해서 loop가 실행될 때마다 1이 <code>i</code> (<code>i++</code>)에 추가되고, 프로세스가 다시 시작된다.</li> + </ol> + </li> + <li><code>i</code>의 값이 <code>cats.length</code>같아질때, loop는 멈추고, 브라우저는 loop 아래의 다음 코드로 넘어가게된다.</li> +</ol> + +<div class="note"> +<p><strong>Note</strong>: 컴퓨터는 1이 아닌 0부터 계산하기 때문에 exit 조건을<code>i <= cats.length</code>이 아닌 <code>i < cats.length</code>로 설정했다. — 우리는 <code>i</code> 를 <code>0</code>에서 시작해서, <code>i = 4</code> (배열의 마지막 index 항목)까지 실행한다. <code>cats.length</code> 는 5개의 항목을 가지고있어 5까지 반환하지만 우리는 <code>i = 5</code>까지의 값을 원하지 않으므로 마지막 항목은 <code>undefined</code>를 반환하게 된다.(그래서 index가 5인 배열 항목이 존재하지 않는다.)그러므로 <code>cats.length</code> (<code>i <=</code>) 를 쓰지 않고 <code>cats.length</code> (<code>i <</code>)로 만들었다.</p> +</div> + +<div class="note"> +<p><strong>Note</strong>: exit조건의 공통적인 실수는 "작거나 같다" (<code><=</code>)를 사용하는것보다 "동등"(<code>===</code>)을 사용하는것이다 . 만약 우리가 <code>i = 5</code>까지 loop를 사용한다면 exit 조건은 <code>i <= cats.length</code>가 되어야 한다. 만약 우리가 <code>i === cats.length</code>로 설정한다면 그 loop는 전부를 실행하지 않을것이다 왜냐하면 <code>i</code>는 첫번째 loop에서 <code>5</code>와 같지 않기 때문에 작업이 즉시 중단된다. </p> +</div> + +<p>우리는 마지막으로 출력되는 문장이 잘 만들어지지 않았다는 작은 문제를 가지고 있다.:</p> + +<blockquote> +<p>My cats are called Bill, Jeff, Pete, Biggles, Jasmin,</p> +</blockquote> + +<p>이상적으로 우리는 문장의 마지막에 쉼표가 없도록 마지막 loop 반복에서 연결을 변경하는것을 원한다 — 우리는 for loop 내부에서 조건부를 넣어서 이 특별한 경우를 처리할수 있다:</p> + +<pre class="brush: js notranslate">for (let i = 0; i < cats.length; i++) { + if (i === cats.length - 1) { + info += 'and ' + cats[i] + '.'; + } else { + info += cats[i] + ', '; + } +}</pre> + +<div class="note"> +<p><strong>Note</strong>: 너는 <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/basic-for-improved.html">example code on GitHub</a> too (also <a href="http://mdn.github.io/learning-area/javascript/building-blocks/loops/basic-for-improved.html">see it running live</a>)에서 예제를 찾아볼수있다.</p> +</div> + +<div class="warning"> +<p><strong>중요</strong>: With for — 모든 loop와 마찬가지로 — initializer 가 반복되어 결국 종료 조건에 도달하는지 확인해야 한다. 그렇지 않으면 loop가 영원히 계속되고 브라우저가 강제로 중지 시키거나 충돌하게 된다. 이를 우리는 <strong>infinite loop(무한 루프)</strong>라 한다.</p> +</div> + +<h2 id="Break을_가지고있는_loops">Break을 가지고있는 loops</h2> + +<p>만약 너가 모든 반복이 완료되기 전에 loop를 종료하려면 <a href="/en-US/docs/Web/JavaScript/Reference/Statements/break">break</a> 문을 사용할수 있다. 우리는 이미 이전 설명에서 <a href="/en-US/Learn/JavaScript/Building_blocks/conditionals#switch_statements">switch statements</a>을 본적이 있다. — 입력 식과 일치하는 switch 문에서 case가 충족되면 break 문은 switch 문을 즉시 종료하고 그 뒤에 코드로 이동한다.</p> + +<p>이것은 loop와 같다. — <code>break</code> 문은 즉시 loop를 빠져 나와 브라우저가 그 다음에 나오는 코드로 이동하게 한다.</p> + +<p>여러 연락처와 전화 번호를 검색하여 찾고자 하는 번호 만 반환하고 싶다고 해보자 먼저 간단한 HTML — 우리가 검색할 이름을 입력 할 수 잇께 해주는 텍스트 {{htmlelement("input")}}, 검색 제출을 위한 {{htmlelement("button")}}요소, 그리고 {{htmlelement("p")}} 요소를 사용해 결과를 표시하자:</p> + +<pre class="brush: html notranslate"><label for="search">Search by contact name: </label> +<input id="search" type="text"> +<button>Search</button> + +<p></p></pre> + +<p>이제 JavaScript를 보자:</p> + +<pre class="brush: js notranslate">const contacts = ['Chris:2232322', 'Sarah:3453456', 'Bill:7654322', 'Mary:9998769', 'Dianne:9384975']; +const para = document.querySelector('p'); +const input = document.querySelector('input'); +const btn = document.querySelector('button'); + +btn.addEventListener('click', function() { + let searchName = input.value; + input.value = ''; + input.focus(); + for (let i = 0; i < contacts.length; i++) { + let splitContact = contacts[i].split(':'); + if (splitContact[0] === searchName) { + para.textContent = splitContact[0] + '\'s number is ' + splitContact[1] + '.'; + break; + } else { + para.textContent = 'Contact not found.'; + } + } +});</pre> + +<div class="hidden"> +<h6 id="Hidden_code_3">Hidden code 3</h6> + +<pre class="brush: html notranslate"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>Simple contact search example</title> + <style> + + </style> + </head> + <body> + + <label for="search">Search by contact name: </label> + <input id="search" type="text"> + <button>Search</button> + + <p></p> + + + <script> + const contacts = ['Chris:2232322', 'Sarah:3453456', 'Bill:7654322', 'Mary:9998769', 'Dianne:9384975']; + const para = document.querySelector('p'); + const input = document.querySelector('input'); + const btn = document.querySelector('button'); + + btn.addEventListener('click', function() { + let searchName = input.value; + input.value = ''; + input.focus(); + for (let i = 0; i < contacts.length; i++) { + let splitContact = contacts[i].split(':'); + if (splitContact[0] === searchName) { + para.textContent = splitContact[0] + '\'s number is ' + splitContact[1] + '.'; + break; + } else if (i === contacts.length-1) + para.textContent = 'Contact not found.'; + } + }); + </script> + + </body> +</html></pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_code_3', '100%', 100, "", "", "hide-codepen-jsfiddle") }}</p> + +<ol> + <li>우선 우리는 몇 가지 변수 정의를 한다. 우리는 각 항목이 콜론(:)으로 구분 된 이름과 전화 번호를 포함하는 문자열인 연락처 정보 배열을 가지고 있다.</li> + <li>그 다음에는 버튼 (<code>btn</code>)에 EventListener에 연결하여 버튼을 누르면 검색을 수행하고 결과를 반환하는 코드를 실행한다.</li> + <li>텍스트 input을 비우고 text input 에 focus를 두기 전에, 다음 검색을 준비하기위해 <code><font face="Arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;">텍스트 input에 입력한 값을 </span></font>searchName</code>이라는 변수에 저장한다. </li> + <li>이제 for 반복문의 흥미로운 점을 보자: + <ol> + <li><code><font face="Arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;">카운터를 </span></font>0</code>에서 시작하고 카운터가 <code>contacts.length</code> 보다 커지지 않을때 까지 loop를 실행하고 <code>i</code> 를 1씩 증가시킨다.</li> + <li>반복문 내부에서 먼저 콜론 문자에서 현재 연락처(<code>contacts[i]</code>) 를 나누고 결과값이 두 값을<code>splitContact</code>라는 배열에 저장한다.</li> + <li><code><font face="Arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;">그런 다음 </span></font>splitContact[0]</code> (the contact's name)의 값과 입력된 값 <code>searchName</code>이 같은지 조건문을 이용하여 테스트한다. 두값이 같은 경우, 우리는 para 값에 문자열을 입력하여 연락처 번호를 알린후 <code>break</code> 을 사용하여 loop를 종료한다.</li> + </ol> + </li> + <li> + <p>연락처 이름<code>(contacts.length-1)</code> 을 반복한 후 연락처 이름이 입력 된 검색과 일치 하지 않으면 단락 텍스트가 "연락처 를 찾을 수 없습니다."로 설정되고 반복문이 계속 반복된다.</p> + </li> +</ol> + +<div class="note"> +<p>Note: 너는 <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/contact-search.html">full source code on GitHub</a> too (also <a href="http://mdn.github.io/learning-area/javascript/building-blocks/loops/contact-search.html">see it running live</a>) 에서 전체 코드를 볼수있다.</p> +</div> + +<h2 id="Continue로_반복_건너뛰기">Continue로 반복 건너뛰기</h2> + +<p><a href="/en-US/docs/Web/JavaScript/Reference/Statements/continue">continue</a>문은 <code>break</code>과 비슷한 방식으로 작동하지만 loop에서 완전히 벗어나는 대신 loop의 다음 반복으로 건너 뛰게된다. 숫자를 입력으로 사용하고 정수의 제곱 인 숫자 (정수)만 반환하는 또 다른 예를 살펴보자.</p> + +<p>HTML 코드는 기본적으로 마지막 예제와 같다 — 간단한 텍스트 입력 및 출력을 위한 단락, loop자체가 약간 다르긴 하지만 JavaScript는 대부분 동일하다 :</p> + +<pre class="brush: js notranslate">let num = input.value; + +for (let i = 1; i <= num; i++) { + let sqRoot = Math.sqrt(i); + if (Math.floor(sqRoot) !== sqRoot) { + continue; + } + + para.textContent += i + ' '; +}</pre> + +<p>여기에서 출력값을 볼수있다:</p> + +<div class="hidden"> +<h6 id="Hidden_code_4">Hidden code 4</h6> + +<pre class="brush: html notranslate"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>Integer squares generator</title> + <style> + + </style> + </head> + <body> + + <label for="number">Enter number: </label> + <input id="number" type="text"> + <button>Generate integer squares</button> + + <p>Output: </p> + + + <script> + const para = document.querySelector('p'); + const input = document.querySelector('input'); + const btn = document.querySelector('button'); + + btn.addEventListener('click', function() { + para.textContent = 'Output: '; + let num = input.value; + input.value = ''; + input.focus(); + for (let i = 1; i <= num; i++) { + let sqRoot = Math.sqrt(i); + if (Math.floor(sqRoot) !== sqRoot) { + continue; + } + + para.textContent += i + ' '; + } + }); + </script> + + </body> +</html></pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_code_4', '100%', 100, "", "", "hide-codepen-jsfiddle") }}</p> + +<ol> + <li>이 경우에 입력된 값은 숫자(<code>num</code>)여야 한다. <code>for</code> loop는 1에서 시작하는 카운터(이 경우에는 0에 관심이 없기 때문에), 카운터가 입력 <code>num</code> 보다 커질 때 루프가 중지 될 것이라고 말하는 종료 조건 및 매회 마다 1씩 증가되는 반복자가 주어진다.</li> + <li>Loop 내에서<a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sqrt">Math.sqrt(i)</a>를 사용하여 숫자의 제곱근을 찾은 다음 제곱근이 가장 가까운 정수로 반올림 된 경우와 같은지 테스트 하여 제곱근이 정수인지 확인한다. <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/floor">Math.floor()</a>가 전달받은 숫자에 대해 정수로 바꿔준다.</li> + <li>만약 제곱근과 정수로 바뀐 제곱근이 서로 같지 않다면(<code>!==</code>) 제곱근이 정수가 아니므로 관심이 없다. 이 경우<code>continue</code> 문을 사용하여 번호를 기록하지 않고 다음 루프 반복으로 건너 뛴다.</li> + <li><code><font face="Arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;">만약 제곱근이 정수 인 경우 </span></font>continue</code> 문이 실행되지 않도록 if 블록을 지나치게 건너 뛴다. 대신 현재 <code>i</code> 값과 단락 내용 의 끝 부분에 공백을 연결한다.</li> +</ol> + +<div class="note"> +<p><strong>Note</strong>: 너는 <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/integer-squares.html">full source code on GitHub</a> too (also <a href="http://mdn.github.io/learning-area/javascript/building-blocks/loops/integer-squares.html">see it running live</a>)에서 전체 코드를 볼수 있다.</p> +</div> + +<h2 id="while_그리고_do_..._while">while 그리고 do ... while</h2> + +<p><code>for</code> 는 JavaScript에서 사용할 수 잇는 유일한 유형의 loop가 아니다. 실제로 많은 다른 것들이 있따. 지금 모든 것을 이해할 필요는 없지만 약간 다른 방식으로 같은 기능을 인식 할 수 있도록 몇 가지 다른 구조를 살펴 보는것이 좋다.</p> + +<p>먼저 <a href="/en-US/docs/Web/JavaScript/Reference/Statements/while">while</a> loop를 살펴보자 이 loop의 구문은 다음과 같다:</p> + +<pre class="notranslate">initializer +while (exit-condition) { + // code to run + + final-expression +}</pre> + +<p>이는 for loop와 매우 비슷하게 작동한다. 단, initializer 변수가 loop 앞에 설정되어 있고, final-expression이 실행되는 코드 다음에 loop 내에 포함되어 있지 않다. 이 두개가 괄호 안에 포함되어 있지 않다. exit-조건은 괄호 안에 포함되며 <code>for</code>대신 <code>while</code> 키워드가 온다.</p> + +<p>같은 세 가지 항목이 여전히 존재하며 for loop와 동일한 순서로 정의되어 있다. exit 조건에 도달햇는지 여부를 확인 하기 전에 initializer를 정의해야 하므로 의미가 있다. loop 내부의 코드가 실행 된 후 최종 조건이 실행되고 (반복이 완료 되었다.) 이는 exit 조건에 아직 도달하지 않은 경우에만 발생한다. </p> + +<p>고양이 목록 예제를 다시 한번 살펴 보자 while loop를 사용하도록 다시 작성해 보자:</p> + +<pre class="brush: js notranslate">let i = 0; + +while (i < cats.length) { + if (i === cats.length - 1) { + info += 'and ' + cats[i] + '.'; + } else { + info += cats[i] + ', '; + } + + i++; +}</pre> + +<div class="note"> +<p><strong>Note</strong>: 이것은 여전히 예상하는 바와 똑같이 작동한다 <a href="http://mdn.github.io/learning-area/javascript/building-blocks/loops/while.html">running live on GitHub</a> (also view the <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/while.html">full source code</a>).</p> +</div> + +<p><a href="/en-US/docs/Web/JavaScript/Reference/Statements/do...while">do...while</a> loop 는 많이 비슷하지만 while 구조에 변형을 제공한다:</p> + +<pre class="notranslate">initializer +do { + // code to run + + final-expression +} while (exit-condition)</pre> + +<p>이 경우 루프가 시작되기 전에 initializer가 다시 시작된다. <code>do</code> 키워드 는 실행할 코드와 최종 표현식을 포함하는 중괄호 바로 앞에 온다.</p> + +<p><code><font face="Arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;">여기서 차별화 요소는 종료 조건이 그 밖의 모든 것 다음에 괄호로 묶여 있고 </span></font>while</code> 키워드로 시작한다는 것이다. <code>do...while</code> loop 에서 중괄호 안의 코드는 체크가 실행되기 전에 항상 한 번 실행되어 다시 실행되어야 하는지를 확인한다.( 체크가 먼저 오면 코드가 실행 되지 않을 수도 있다.)</p> + +<p><code>do...while</code> loop를 사용하기 위해 고양이 목록 예제를 다시 작성해 보자:</p> + +<pre class="brush: js notranslate">let i = 0; + +do { + if (i === cats.length - 1) { + info += 'and ' + cats[i] + '.'; + } else { + info += cats[i] + ', '; + } + + i++; +} while (i < cats.length);</pre> + +<div class="note"> +<p><strong>Note</strong>: 다시 말하지만 이것은 예상했던 것과 똑같이 작동한다. <a href="http://mdn.github.io/learning-area/javascript/building-blocks/loops/do-while.html">running live on GitHub</a> (also view the <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/do-while.html">full source code</a>).</p> +</div> + +<div class="warning"> +<p><strong>중요</strong>: while과 do ... while - while - 모든 loop와 마찬가지로 - initalizer 가 반복 되어 결국 종료 조건에 도달하는지 확인해야 한다. 그렇지 않으면 loop는 영원히 계속되고 브라우저가 강제로 종료 시키거나 충돌한다. 이를 <strong>infinite loop(무한 루프)라한다</strong>.</p> +</div> + +<h2 id="활동_학습_카운트_다운_시작!">활동 학습: 카운트 다운 시작!</h2> + +<p>이 연습에서 출력 상자에 간단한 발사 카운트 다운을 인쇄하여 특히 우리가 원하는10에서 Blast off로 출력한다:</p> + +<ul> + <li>Loop를 10에서 0으로 반복한다 initializer — <code>let i = 10;</code>.</li> + <li>반복 할때 마다 새로운 단락을 만들어 <code>const output = document.querySelector('.output');</code> 를 사용하여 <code><div></code>에 추가한다. comments에서 우리는 loop의 어딘가에 사용되어야하는 세 개의 코드 라인을 제공했다: + <ul> + <li><code>const para = document.createElement('p');</code> — 새로운 단락 생성.</li> + <li><code>output.appendChild(para);</code> — 문단을 <code><div></code>에 추가</li> + <li><code>para.textContent =</code> — 단락 안의 텍스트를 등호 다음에 오른쪽에 놓은 것과 동일하게 만든다.</li> + </ul> + </li> + <li><code><font face="Arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;">다른 반복 숫자는 해당 반복에 대한 단락에 다른 텍스트를 넣어야한다.(조건문과 여러 문장이 필요하다 </span></font>para.textContent =</code> lines): + <ul> + <li>숫자가 10이면 단락에 "카우트 다운 10."을 출력해라</li> + <li>숫자가 0이면 "Blast off!"라고 단락에 출력해라.</li> + <li>다른 번호의 경우 단락에 숫자만 출력해라.</li> + </ul> + </li> + <li>반복자를 포함하는 것을 잊지 말아라! 그리고 이 예제에서 각각의 반복 후에 숫자가 증가되는게 아니게 카운트 다운을 하고있다.너는 <code>i++</code> 원하지 <strong>않는다.</strong>— 어떻게 아래로 반복시킬까?</li> +</ul> + +<p>만약 실수를 한 경우 "재설정" 버튼을 사용하여 예제를 얼마든지 재설정 할수 있다. 정말 모르겠다면 "soultion보기"를 눌러 풀이를 보자</p> + +<div class="hidden"> +<h6 id="Active_learning">Active learning</h6> + +<pre class="brush: html notranslate"><h2>Live output</h2> +<div class="output" style="height: 410px;overflow: auto;"> + +</div> + +<h2>Editable code</h2> +<p class="a11y-label">Press Esc to move focus away from the code area (Tab inserts a tab character).</p> +<textarea id="code" class="playable-code" style="height: 300px;width: 95%"> +let output = document.querySelector('.output'); +output.innerHTML = ''; + +// let i = 10; + +// const para = document.createElement('p'); +// para.textContent = ; +// output.appendChild(para); +</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Reset"> + <input id="solution" type="button" value="Show solution"> +</div> +</pre> + +<p class="brush: js"></p> + +<p class="brush: js"></p> + +<p class="brush: js"></p> + +<pre class="brush: css notranslate">html { + font-family: sans-serif; +} + +h2 { + font-size: 16px; +} + +.a11y-label { + margin: 0; + text-align: right; + font-size: 0.7rem; + width: 98%; +} + +body { + margin: 10px; + background: #f5f9fa; +}</pre> + +<p class="brush: js"></p> + +<p class="brush: js"></p> + +<p class="brush: js"></p> + +<p class="brush: js"></p> + +<pre class="brush: js notranslate">const textarea = document.getElementById('code'); +const reset = document.getElementById('reset'); +const solution = document.getElementById('solution'); +let code = textarea.value; +let userEntry = textarea.value; + +function updateCode() { + eval(textarea.value); +} + +reset.addEventListener('click', function() { + textarea.value = code; + userEntry = textarea.value; + solutionEntry = jsSolution; + solution.value = 'Show solution'; + updateCode(); +}); + +solution.addEventListener('click', function() { + if(solution.value === 'Show solution') { + textarea.value = solutionEntry; + solution.value = 'Hide solution'; + } else { + textarea.value = userEntry; + solution.value = 'Show solution'; + } + updateCode(); +}); + +let jsSolution = 'let output = document.querySelector(\'.output\');\noutput.innerHTML = \'\';\n\nlet i = 10;\n\nwhile(i >= 0) {\n let para = document.createElement(\'p\');\n if(i === 10) {\n para.textContent = \'Countdown \' + i;\n } else if(i === 0) {\n para.textContent = \'Blast off!\';\n } else {\n para.textContent = i;\n }\n\n output.appendChild(para);\n\n i--;\n}'; +let solutionEntry = jsSolution; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); + +// stop tab key tabbing out of textarea and +// make it write a tab at the caret position instead + +textarea.onkeydown = function(e){ + if (e.keyCode === 9) { + e.preventDefault(); + insertAtCaret('\t'); + } + + if (e.keyCode === 27) { + textarea.blur(); + } +}; + +function insertAtCaret(text) { + let scrollPos = textarea.scrollTop; + let caretPos = textarea.selectionStart; + + let front = (textarea.value).substring(0, caretPos); + let back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length); + textarea.value = front + text + back; + caretPos = caretPos + text.length; + textarea.selectionStart = caretPos; + textarea.selectionEnd = caretPos; + textarea.focus(); + textarea.scrollTop = scrollPos; +} + +// Update the saved userCode every time the user updates the text area code + +textarea.onkeyup = function(){ + // We only want to save the state when the user code is being shown, + // not the solution, so that solution is not saved over the user code + if(solution.value === 'Show solution') { + userEntry = textarea.value; + } else { + solutionEntry = textarea.value; + } + + updateCode(); +};</pre> + +<p class="brush: js"></p> +</div> + +<p>{{ EmbedLiveSample('Active_learning', '100%', 880, "", "", "hide-codepen-jsfiddle") }}</p> + +<h2 id="활동_학습_손님_목록_작성">활동 학습: 손님 목록 작성</h2> + +<p>이 연습에서 배열에 저장된 이름 목록을 가져 와서 손님 목록에 넣기를 원한다. 그러나 그것은 쉽지 않다. — 우리는 Phil과 Lola가 욕심 많고 무례하고, 항상 모든 음식을 먹기 때문에 Phil과 Lola를 들여 보내고 싶지 않다. 우리는 초대할 손님 목록과 거절할 손님목록을 가지고 있다.</p> + +<p>특히, 우리가 너에게 원하는 것:</p> + +<ul> + <li><code><font face="Arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;">0부터 </span></font>people</code> 배열의 길이까지 반복 할 loop를 작성해라. <code>let i = 0;</code> 를 initializer 로 시작해야 하지만 종료 조건은 무엇일까?</li> + <li>각 loop 반복 중에 조건문을 사용하여 현재 배열 항목이 "Phil"또는 "Lola"와 같은지 확인해라: + <ul> + <li>그럴 경우 배열 항목을 <code>refused</code> 된 단락의 <code>textContent</code>, 끝에 쉽표와 공백을 붙여 연결해라 .</li> + <li>그렇지 않은 경우 배열 항목을 <code>admitted</code> 된단락의 <code>textContent</code>, 끝에 연결하고 뒤에 쉼표와 공백을 붙인다.</li> + </ul> + </li> +</ul> + +<p>우리는 너에게 이미 아래의 것들을 제공했다:</p> + +<ul> + <li><code>let i = 0;</code> — 너의 initializer.</li> + <li><code>refused.textContent +=</code> — <code>refused.textContent</code> 의 끝까지 무언가를 연결할 라인의 시작</li> + <li><code>admitted.textContent +=</code> — <code>admitted.textContent</code> 의 끝까지 무언가를 연결할 행의 시작 부분이다.</li> +</ul> + +<p>추가 보너스 질문 — 위의 작업을 성공적으로 마친 후에는 쉼표로 구분 된 두 개의 이름 목록이 남지만 정리되지 않는다. 각 끝에 쉼표가 표시된다. 각각의 경우에 마지막 쉼표를 잘라내는 줄을 작성하는 방법을 알아 내고 마지막에 모든것을 멈추는 코드를 추가할수 있겠어? 도움이 되는 <a href="/en-US/docs/Learn/JavaScript/First_steps/Useful_string_methods">Useful string methods</a> 도움말을 읽어봐라.</p> + +<p>실수를 한 경우 "재설정"버튼을 사용하여 예제를 언제든지 재설정 할 수 있다. 정말 힘들다면 "solution보기"를 눌러 풀이를 확인할수 있다.</p> + +<div class="hidden"> +<h6 id="Active_learning_2">Active learning 2</h6> + +<pre class="brush: html notranslate"><h2>Live output</h2> +<div class="output" style="height: 100px;overflow: auto;"> + <p class="admitted">Admit: </p> + <p class="refused">Refuse: </p> +</div> + +<h2>Editable code</h2> +<p class="a11y-label">Press Esc to move focus away from the code area (Tab inserts a tab character).</p> +<textarea id="code" class="playable-code" style="height: 400px;width: 95%"> +const people = ['Chris', 'Anne', 'Colin', 'Terri', 'Phil', 'Lola', 'Sam', 'Kay', 'Bruce']; + +const admitted = document.querySelector('.admitted'); +const refused = document.querySelector('.refused'); +admitted.textContent = 'Admit: '; +refused.textContent = 'Refuse: ' + +// let i = 0; + +// refused.textContent += ; +// admitted.textContent += ; + +</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Reset"> + <input id="solution" type="button" value="Show solution"> +</div> +</pre> + + + + + +<pre class="brush: css notranslate">html { + font-family: sans-serif; +} + +h2 { + font-size: 16px; +} + +.a11y-label { + margin: 0; + text-align: right; + font-size: 0.7rem; + width: 98%; +} + +body { + margin: 10px; + background: #f5f9fa; +}</pre> + + + + + + + + + +<pre class="brush: js notranslate">const textarea = document.getElementById('code'); +const reset = document.getElementById('reset'); +const solution = document.getElementById('solution'); +let code = textarea.value; +let userEntry = textarea.value; + +function updateCode() { + eval(textarea.value); +} + +reset.addEventListener('click', function() { + textarea.value = code; + userEntry = textarea.value; + solutionEntry = jsSolution; + solution.value = 'Show solution'; + updateCode(); +}); + +solution.addEventListener('click', function() { + if(solution.value === 'Show solution') { + textarea.value = solutionEntry; + solution.value = 'Hide solution'; + } else { + textarea.value = userEntry; + solution.value = 'Show solution'; + } + updateCode(); +}); + +let jsSolution = 'const people = [\'Chris\', \'Anne\', \'Colin\', \'Terri\', \'Phil\', \'Lola\', \'Sam\', \'Kay\', \'Bruce\'];\n\nconst admitted = document.querySelector(\'.admitted\');\nconst refused = document.querySelector(\'.refused\');\n\nadmitted.textContent = \'Admit: \';\nrefused.textContent = \'Refuse: \'\nlet i = 0;\n\ndo {\n if(people[i] === \'Phil\' || people[i] === \'Lola\') {\n refused.textContent += people[i] + \', \';\n } else {\n admitted.textContent += people[i] + \', \';\n }\n i++;\n} while(i < people.length);\n\nrefused.textContent = refused.textContent.slice(0,refused.textContent.length-2) + \'.\';\nadmitted.textContent = admitted.textContent.slice(0,admitted.textContent.length-2) + \'.\';'; +let solutionEntry = jsSolution; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); + +// stop tab key tabbing out of textarea and +// make it write a tab at the caret position instead + +textarea.onkeydown = function(e){ + if (e.keyCode === 9) { + e.preventDefault(); + insertAtCaret('\t'); + } + + if (e.keyCode === 27) { + textarea.blur(); + } +}; + +function insertAtCaret(text) { + let scrollPos = textarea.scrollTop; + let caretPos = textarea.selectionStart; + + let front = (textarea.value).substring(0, caretPos); + let back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length); + textarea.value = front + text + back; + caretPos = caretPos + text.length; + textarea.selectionStart = caretPos; + textarea.selectionEnd = caretPos; + textarea.focus(); + textarea.scrollTop = scrollPos; +} + +// Update the saved userCode every time the user updates the text area code + +textarea.onkeyup = function(){ + // We only want to save the state when the user code is being shown, + // not the solution, so that solution is not saved over the user code + if(solution.value === 'Show solution') { + userEntry = textarea.value; + } else { + solutionEntry = textarea.value; + } + + updateCode(); +};</pre> + + + + +</div> + +<p>{{ EmbedLiveSample('Active_learning_2', '100%', 680, "", "", "hide-codepen-jsfiddle") }}</p> + +<h2 id="어떤_loop종류를_사용하나">어떤 loop종류를 사용하나?</h2> + +<p>기본적으로 <code>for</code>, <code>while</code>, 그리고 <code>do...while</code> loops 는 상호 교환이 가능하다. 그들은 모두 동일한 문제를 해결하는 데 사용할수 있으며, 사용하는 것은 주로 개인의 취향에 달려 있다. 가장 기억하기 쉽거나 가장 직관적인 방법을 찾아라. 다시 한번 살펴보자.</p> + +<p>First <code>for</code>:</p> + +<pre class="notranslate">for (initializer; exit-condition; final-expression) { + // code to run +}</pre> + +<p><code>while</code>:</p> + +<pre class="notranslate">initializer +while (exit-condition) { + // code to run + + final-expression +}</pre> + +<p>and finally <code>do...while</code>:</p> + +<pre class="notranslate">initializer +do { + // code to run + + final-expression +} while (exit-condition)</pre> + +<p><font face="Arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;">우리는 적어도 </span></font><code>for</code>를 <font face="Arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;">처음에는 모든 것중에 기억하는 것이 가장 쉽기 때문에 추천한다. </span></font>— initializer, exit 조건 및 최종 표현식은 모두 괄호 안에 깔끔하게 들어가야 하므로 어디에 있는지 쉽게 알 수 있다. 너가 그것들을 놓치지 않게 잘 점검해보자.</p> + +<div class="note"> +<p><strong>Note</strong>: 고급 / 특수한 상황에서 나아가 다른 loop 유형 / 기능도 있다. loop 학습으로 더 자세히 알고 싶다면 <a href="/en-US/docs/Web/JavaScript/Guide/Loops_and_iteration">Loops and iteration guide</a> 를 읽어보자.</p> +</div> + +<h2 id="결론">결론</h2> + +<p>이 설명에서는 기본 개념과 JavaScript에서 반복되느 코드를 사용할 수 있는 여러 가지 옵션에 대해 설명했다. 이제 loop가 반복적 인 코드를 처리하는 좋은 메커니즘 인 이유를 명확히 파악하고 자신의 예제에서 사용하도록 노력해야한다!</p> + +<p>만약 이해가 되지 않는 내용이 있으면 다시 내용을 읽어보거나 <a href="/en-US/Learn#Contact_us">contact us</a> 를 통해 도움을 요청하자.</p> + +<h2 id="또한_볼것">또한 볼것</h2> + +<ul> + <li><a href="/en-US/docs/Web/JavaScript/Guide/Loops_and_iteration">Loops and iteration in detail</a></li> + <li><a href="/en-US/docs/Web/JavaScript/Reference/Statements/for">for statement reference</a></li> + <li><a href="/en-US/docs/Web/JavaScript/Reference/Statements/while">while</a> and <a href="/en-US/docs/Web/JavaScript/Reference/Statements/do...while">do...while</a> references</li> + <li><a href="/en-US/docs/Web/JavaScript/Reference/Statements/break">break</a> and <a href="/en-US/docs/Web/JavaScript/Reference/Statements/continue">continue</a> references</li> + <li> + <p class="entry-title"><a href="https://www.impressivewebs.com/javascript-for-loop/">What’s the Best Way to Write a JavaScript For Loop?</a> — some advanced loop best practices</p> + </li> +</ul> + +<p>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/conditionals","Learn/JavaScript/Building_blocks/Functions", "Learn/JavaScript/Building_blocks")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/conditionals">Making decisions in your code — conditionals</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Looping_code">Looping code</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions">Functions — reusable blocks of code</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Build_your_own_function">Build your own function</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Return_values">Function return values</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events">Introduction to events</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Image_gallery">Image gallery</a></li> +</ul> diff --git a/files/ko/learn/javascript/building_blocks/조건문/index.html b/files/ko/learn/javascript/building_blocks/조건문/index.html new file mode 100644 index 0000000000..858d6f9116 --- /dev/null +++ b/files/ko/learn/javascript/building_blocks/조건문/index.html @@ -0,0 +1,770 @@ +--- +title: Making decisions in your code — 조건문 +slug: Learn/JavaScript/Building_blocks/조건문 +translation_of: Learn/JavaScript/Building_blocks/conditionals +--- +<div>{{LearnSidebar}}</div> + +<div>{{NextMenu("Learn/JavaScript/Building_blocks/Looping_code", "Learn/JavaScript/Building_blocks")}}</div> + +<p class="summary">어떤 프로그래밍 언어든 코드는 의사 결정을 내리고 입력 내용에 따라 작업을 수행해야합니다. 예를 들어 게임에서 플레이어의 생명 수치가 0이면 게임이 종료됩니다. 날씨 앱에서는 아침에 해가 뜬 그림을 보여주고 밤에는 달과 별을 보여줍니다. 이 문서에서는 JavaScript에서 조건문이 작동하는 방법을 살펴 보겠습니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">선행 조건:</th> + <td> + <p>기본적인 컴퓨터 활용 능력, HTML, CSS, <a href="/ko/docs/Learn/JavaScript/First_steps">Javascript 첫 걸음</a></p> + </td> + </tr> + <tr> + <th scope="row">목표:</th> + <td> + <p>자바스크립트에서 조건문의 사용법을 이해합니다.</p> + </td> + </tr> + </tbody> +</table> + +<h2 id="당신은_하나의_조건을_가질_수_있습니다.">당신은 하나의 조건을 가질 수 있습니다.</h2> + +<p>사람(과 동물)은 작은 것(과자를 하나 먹을까? 두개 먹을까?)부터 큰 것(고향에 머물면서 아버지의 농장에서 일해야 할까? 아니면 천체물리학을 공부하러 미국으로 유학을 갈까?)까지 자신의 경험을 바탕으로 결정합니다.</p> + +<p>조건문은 결정해야 하는 선택(예를 들면, "과자 하나? 두 개?)부터 선택의 결과(과자를 하나 먹으면 여전히 배고플 수 있고, 두 개를 먹으면 배는 부르지만, 엄마한테 과자를 다 먹었다고 혼날 수 있다)까지 자바스크립트에서 의사 결정을 내릴 수 있습니다. </p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13703/cookie-choice-small.png" style="display: block; margin: 0 auto;"></p> + +<h2 id="if_..._else_문">if ... else 문</h2> + +<p>자바스크립트에서 사용하는 조건문 중에서 가장 일반적인 유형을 봅시다. — the humble <code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/if...else">if ... else</a></code><a href="/en-US/docs/Web/JavaScript/Reference/Statements/if...else"> statement</a>.</p> + +<h3 id="if_..._else_문법">if ... else 문법</h3> + +<p><code>if...else</code> 문법은 {{glossary("pseudocode")}} 다음과 같습니다:</p> + +<pre class="notranslate">if (condition) { + code to run if condition is true +} else { + run some other code instead +}</pre> + +<p>Here we've got:</p> + +<ol> + <li>키워드 <code>if</code> 뒤에 괄호가 옵니다.</li> + <li>시험할 조건은 괄호 안에 위치합니다. (전형적으로 "이 값이 다른 값보다 큰지", "이 값이 존재하는지") 이 조건은 마지막 모듈에서 논의했던 비교연산자(<a href="/en-US/Learn/JavaScript/First_steps/Math#Comparison_operators">comparison operators</a>)를 사용할 것이고 <code>true</code> 나 <code>false</code>를 리턴합니다.</li> + <li>내부의 중괄호 안에 코드가 있습니다. — 이것은 우리가 좋아하는 코드일 수 있고, 조건이 <code>true</code>를 반환하는 경우에만 실행됩니다.</li> + <li>키워드 <code>else</code>.</li> + <li>또 다른 중괄호 안에 더 많은 코드가 있습니다. — 이것은 우리가 좋아하는 코드 일 수 있고, 조건이 <code>true</code>가 아닌 경우에만 실행됩니다.</li> +</ol> + +<p>이 코드는 사람이 읽을 수 있습니다. — "만약 조건이 <code>true</code>면, 코드 A를 실행하고, 아니면 코드 B를 실행한다." 라고 말합니다.</p> + +<p>반드시 <code>else</code>와 두 번째 중괄호를 포함하지 않아도 된다는 것을 주목해야 합니다. — 다음은 또한 완벽한 코드입니다.:</p> + +<pre class="notranslate">if (condition) { + code to run if condition is true +} + +run some other code</pre> + +<p>하지만, 여기서 조심 해야 할 점— 위의 경우, 코드의 두 번째 블록은 조건문에 의해서 제어되지 않습니다. 그래서 조건이 <code>true</code>나 <code>false</code>를 리턴하는 것에 관계없이 항상 동작합니다. 이것이 반드시 나쁜 것은 아니지만, 원하는 대로 되지 않을 수도 있습니다. — 코드의 한 블록이나 다른 블록이 실행되거나 둘 다 실행되지 않는 것을 원할 것입니다.</p> + +<p>마지막으로, 다음과 같이 짧은 스타일로 중괄호 없이 쓰여진 <code>if...else</code>를 볼 수 있었을 것입니다.:</p> + +<pre class="notranslate">if (condition) code to run if condition is true +else run some other code instead</pre> + +<p>이것은 완벽하게 유효한 코드이지만, 사용하는 것을 추천하지 않습니다. — 중괄호를 사용하여 코드를 구분하고, 여러 줄과 들여쓰기를 사용한다면, 코드를 쉽게 읽고, 진행되는 작업을 훨씬 쉽게 처리할 수 있습니다.</p> + +<h3 id="실제_예시">실제 예시</h3> + +<p>문법을 잘 이해하기 위해서 실제 예시를 알아봅시다. 어머니나 아버지가 아이에게 집안일을 도와달라고 요청한다고 상상해 봅시다. 부모님께서 "우리 애기, 만약에 쇼핑 하고 가는 걸 도와주면, 용돈을 더 줄게! 그럼 네가 원하는 걸 살 수 있을거야"라고 말씀 하신다면, 자바스크립트에서 이것을 다음과 같이 표현할 수 있습니다.</p> + +<pre class="brush: js notranslate">var shoppingDone = false; + +if (shoppingDone === true) { + var childsAllowance = 10; +} else { + var childsAllowance = 5; +}</pre> + +<p>위 코드에는 항상 <code>false</code>를 리턴하는 <code>shoppingDone</code>변수를 결과로 얻을 것입니다. 아이에게 실망을 안겨주겠죠. 아이가 부모님과 함께 쇼핑을 간다면 우리가 부모님을 위해 <code>shoppingDone</code>변수를 <code>true</code>로 설정하는 메커니즘을 만들 수 있겠죠.</p> + +<div class="note"> +<p><strong>Note</strong>: GitHub에서 예시를 더 볼 수 있습니다. <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/allowance-updater.html">complete version of this example on GitHub</a> (also see it <a href="http://mdn.github.io/learning-area/javascript/building-blocks/allowance-updater.html">running live</a>.)</p> +</div> + +<h3 id="else_if">else if</h3> + +<p>지난 예시에서는 두 가지 선택과 결과가 있었죠. — 하지만 우리가 두 가지보다 더 많은 선택과 결과를 원한다면?</p> + +<p>추가로 선택/결과를 <code>if...else</code>에 연결하는 방법이 있습니다. — <code>else if</code>를 사용하여. 각 추가 선택은 <code>if() { ... }</code>와 <code>else { ... }</code>사이에 추가적인 블록이 필요합니다. 간단한 날씨 예보 어플리케이션의 일부가 될 수 있는 다음의 예시를 확인하세요. </p> + +<pre class="brush: html notranslate"><label for="weather">Select the weather type today: </label> +<select id="weather"> + <option value="">--Make a choice--</option> + <option value="sunny">Sunny</option> + <option value="rainy">Rainy</option> + <option value="snowing">Snowing</option> + <option value="overcast">Overcast</option> +</select> + +<p></p></pre> + +<pre class="brush: js notranslate">var select = document.querySelector('select'); +var para = document.querySelector('p'); + +select.addEventListener('change', setWeather); + +function setWeather() { + var choice = select.value; + + if (choice === 'sunny') { + para.textContent = 'It is nice and sunny outside today. Wear shorts! Go to the beach, or the park, and get an ice cream.'; + } else if (choice === 'rainy') { + para.textContent = 'Rain is falling outside; take a rain coat and a brolly, and don\'t stay out for too long.'; + } else if (choice === 'snowing') { + para.textContent = 'The snow is coming down — it is freezing! Best to stay in with a cup of hot chocolate, or go build a snowman.'; + } else if (choice === 'overcast') { + para.textContent = 'It isn\'t raining, but the sky is grey and gloomy; it could turn any minute, so take a rain coat just in case.'; + } else { + para.textContent = ''; + } +} + +</pre> + +<p>{{ EmbedLiveSample('else_if', '100%', 100, "", "", "hide-codepen-jsfiddle") }}</p> + +<ol> + <li>여기서 우리는 HTML {{htmlelement("select")}} 엘리먼트를 사용하여 다른 날씨 선택과 간단한 문단을 만들 수 있습니다. </li> + <li>자바스크립트에서 {{htmlelement("select")}} 와 {{htmlelement("p")}} 엘리먼트를 모두 저장하고 있고, <code><select></code> 엘리먼트에 이벤트 리스너를 추가하고, 값이 변할 때 <code>setWeather()</code>함수가 동작합니다.</li> + <li>함수가 동작했을 때, 현재 <code><select></code> 에서 선택된 값을 <code>choice</code>라는 변수에 설정합니다. 그런 다음 조건문을 사용하여 <code>choice</code>값에 따라 문단 안에 다른 텍스트를 표시합니다. <code>if() {...} block</code>에서 테스트된 첫 번째를 제외하고, <code>else if() {...}</code>에서 조건은 테스트되는 방법에 유의하세요.</li> + <li><code>else {...}</code>안의 가장 마지막 선택은 기본적으로 "최후의 수단" 옵션입니다. — <code>true</code>인 조건이 없으면 코드가 실행됩니다. 이 경우 아무것도 선택되지 않으면 예를 들어, 사용자가 처음에 표시한 "Make a choice" placeholder 옵션에서 다시 선택하기로 한다면, 문단의 텍스트를 비우는 역할을 합니다.</li> +</ol> + +<div class="note"> +<p><strong>Note</strong>: You can also <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/simple-else-if.html">find this example on GitHub</a> (<a href="http://mdn.github.io/learning-area/javascript/building-blocks/simple-else-if.html">see it running live</a> on there also.)</p> +</div> + +<h3 id="비교_연산자">비교 연산자</h3> + +<p>비교 연산자는 우리의 조건문 안에 조건을 테스트하는데 사용된다. 우리는 먼저 <a href="/en-US/Learn/JavaScript/First_steps/Math#Comparison_operators">Basic math in JavaScript — numbers and operators</a> 에서 비교 연산자를 봤습니다. </p> + +<ul> + <li><code>===</code>와 <code>!==</code> — 한 값이 다른 값과 같거나 다른지 테스트 한다.</li> + <li><code><</code> 와 <code>></code> — 한 값이 다른 값보다 작은지 큰지 테스트 한다.</li> + <li><code><=</code> 와 <code>>=</code> — 한 값이 다른 값보다 작거나 같은지, 크거나 같은지 테스트 한다</li> +</ul> + +<div class="note"> +<p><strong>Note</strong>: Review the material at the previous link if you want to refresh your memories on these.</p> +</div> + +<p>boolean(<code>true</code>/<code>false</code>)값과 몇 번이고 다시 만날 일반적인 패턴을 테스트하는 것의 특별한 언급을 하고 싶었습니다.. <code>false</code>, <code>undefined</code>, <code>null</code>, <code>0</code>, <code>NaN</code>이나 빈 문자열(<code>''</code>)이 아닌 어떤 값은 조건문이 테스트 되었을 때, <code>true</code>를 리턴합니다.. 그러므로 우리는 변수가 참인지 값이 존재하는지 간단하게 변수 이름을 사용할 수 있습니다.. 예를 들어,</p> + +<pre class="brush: js notranslate">var cheese = 'Cheddar'; + +if (cheese) { + console.log('Yay! Cheese available for making cheese on toast.'); +} else { + console.log('No cheese on toast for you today.'); +}</pre> + +<p>그리고 부모님을 위해 집안일을 하는 아이에 대한 이전 예시에서 리턴하는 것을 다음과 같이 작성할 수 있었습니다.</p> + +<pre class="brush: js notranslate">var shoppingDone = false; + +if (shoppingDone) { // don't need to explicitly specify '=== true' + var childsAllowance = 10; +} else { + var childsAllowance = 5; +}</pre> + +<h3 id="if_..._else_중첩">if ... else 중첩</h3> + +<p><code>if...else</code>문을 다른 문 앞에 넣는 것(중첩하여)은 완벽하게 가능합니다.. 예를 들어, 온도가 무엇인지에 따라 더 많은 선택의 옵션을 보여주기위해 우리의 날씨 예보 어플리케이션에서 업데이트 할 수 있습니다..</p> + +<pre class="brush: js notranslate">if (choice === 'sunny') { + if (temperature < 86) { + para.textContent = 'It is ' + temperature + ' degrees outside — nice and sunny. Let\'s go out to the beach, or the park, and get an ice cream.'; + } else if (temperature >= 86) { + para.textContent = 'It is ' + temperature + ' degrees outside — REALLY HOT! If you want to go outside, make sure to put some suncream on.'; + } +}</pre> + +<p>비록 코드가 모두 동작하더라도, 각 <code>if...else</code>문은 다른 문과 완전히 독립적으로 동작합니다..</p> + +<h3 id="논리_연산자_AND_OR_and_NOT">논리 연산자: AND, OR and NOT</h3> + +<p>만약 중첩된 <code>if...else</code>문을 작성하는 것 없이 다양한 조건을 테스트하길 원한다면 <a href="/en-US/docs/Web/JavaScript/Reference/Operators/Logical_Operators">logical operators</a> 이 당신을 도와줄 수 있습니다. 조건 내에서 사용될 때, 처음 두 가지는 다음과 같이 합니다.</p> + +<ul> + <li><code>&&</code> — AND; <code>true</code>를 리턴하는 전체 표현식을 위해 각각 <code>true</code>계산되는 둘 이상의 표현식을 함께 연결할 수 있습니다.</li> + <li><code>||</code> — OR; <code>true</code>를 리턴하는 전체 표현식을 위해 하나 이상이 <code>true</code>로 계산되는 둘 이상의 표현식을 함께 연결할 수 있습니다.</li> +</ul> + +<p>AND 예시를 위해서 앞의 예제 코드 중에서 다음과 같이 작성할 수 있습니다.</p> + +<pre class="brush: js notranslate">if (choice === 'sunny' && temperature < 86) { + para.textContent = 'It is ' + temperature + ' degrees outside — nice and sunny. Let\'s go out to the beach, or the park, and get an ice cream.'; +} else if (choice === 'sunny' && temperature >= 86) { + para.textContent = 'It is ' + temperature + ' degrees outside — REALLY HOT! If you want to go outside, make sure to put some suncream on.'; +}</pre> + +<p>위 예시에서, 첫 번째 코드 블록은 <code>choice === 'sunny'</code>와 <code>temperature < 86</code>가 <code>true</code>를 리턴한다면 실행될 것입니다.</p> + +<p>빠르게 OR 예시를 봅시다.</p> + +<pre class="brush: js notranslate">if (iceCreamVanOutside || houseStatus === 'on fire') { + console.log('You should leave the house quickly.'); +} else { + console.log('Probably should just stay in then.'); +}</pre> + +<p>논리 연산자의 마지막 유형인 <code>!</code> 연산자로 표현되는 NOT은 표현식을 무효화할 수 있습니다. 위 OR 예시와 함께 봅시다.</p> + +<pre class="brush: js notranslate">if (!(iceCreamVanOutside || houseStatus === 'on fire')) { + console.log('Probably should just stay in then.'); +} else { + console.log('You should leave the house quickly.'); +}</pre> + +<p>위 예시에서, OR 문이 <code>true</code>를 리턴한다면, NOT 연산자는 전체 표현식이 <code>false</code>를 리턴하도록 무효화할 것입니다.</p> + +<p>어떤 구조든지 당신이 원하는 만큼 많은 논리 문을 결합할 수 있습니다. 다음 예시는 두 가지 OR 문 모두 true를 리턴하면, 전체 AND문은 true를 리턴한다는 것을 의미하는 코드를 실행합니다.</p> + +<pre class="brush: js notranslate">if ((x === 5 || y > 3 || z <= 10) && (loggedIn || userName === 'Steve')) { + // run the code +}</pre> + +<p>조건 문에서 논리적 OR 연산자를 사용할 때 일반적인 실수는 값을 한번 체크하는 변수를 명시한 다음, <code>||</code> (OR) 연산로 분리하여 true를 리턴될 수 있는 변수의 리스트를 사용한다는 것입니다. 예를 들어: </p> + +<pre class="example-bad brush: js notranslate">if (x === 5 || 7 || 10 || 20) { + // run my code +}</pre> + +<p>이 경우에 <code>if(...)</code> 내부 조건은 7(또는 다른 0이 아닌 값)이 항상 true가 되므로, 항상 true를 계산할 것입니다. 조건은 "x가 5와 같거나 7이 true면, 항상 그렇다"라고 분명하게 말하고 있습니다. 이것은 논리적으로 우리가 원하는 것이 아닙니다! 이를 동작하게 하기 위해 우리는 각 OR 연산자를 완전하게 명시해야 합니다.</p> + +<pre class="brush: js notranslate">if (x === 5 || x === 7 || x === 10 ||x === 20) { + // run my code +}</pre> + +<h2 id="switch_문">switch 문</h2> + +<p><code>if...else</code> 문은 조건문 코드가 잘 동작되는 일을 하지만, 단점이 없지 않습니다. 그 문은 두 가지 선택을 가지고 있는 경우에 주로 유용합니다. 그리고 각각은 실행되기 위한 합리적인 양의 코드가 필요하고, AND/OR 조건은 복잡합니다.(e.g. 다수의 논리 연산자) 어떤 값의 선택으로 변수를 설정하거나 조건에 따라서 특정 문을 출력하는 경우 구문이 약간 번거로울 수 있습니다. 특히 많은 선택 항목이 있는 경우에 특히 그렇습니다.</p> + +<p><a href="/en-US/docs/Web/JavaScript/Reference/Statements/switch"><code>switch</code> statements</a> 은 당신의 친구입니다. 이는 입력으로 하나의 표현식/값을 받고, 값과 일치하는 하나를 찾을 때까지 여러 항목을 살펴보고 그에 맞는 코드를 실행합니다. 여기 몇몇 많은 수도코드가 있습니다.</p> + +<pre class="notranslate">switch (expression) { + case choice1: + run this code + break; + + case choice2: + run this code instead + break; + + // include as many cases as you like + + default: + actually, just run this code +}</pre> + +<p>여기에서: </p> + +<ol> + <li>뒤에 괄호가 오는 키워드 <code>switch</code>.</li> + <li>괄오 내부에는 표현식이나 값을 입력합니다.</li> + <li>표현식이나 값이 될 수 있는 선택이 따라 오는 키워드 <code>case</code>는 콜론이 뒤에 옵니다.</li> + <li><code>break</code>문은 뒤에 세미콜론이 옵니다. 이전의 선택이 표현식이나 값과 일치한다면 해당 코드 블록에서 실행을 멉추고, switch 문 아래에 있는 어떤 코드로 이동합니다.</li> + <li>원하는 많은 다른 케이스를 입력할 수 있습니다. </li> + <li>키워드 <code>default</code>는 case들과 같은 코드를 입력하고, 일치하는 항목이 없으면 실행되는 기본 옵션입니다. case와 일치하지 않고, 예외가 필요하지 않는 경우 제외할 수 있습니다.</li> +</ol> + +<div class="note"> +<p><strong>Note</strong>: default를 반드시 포함하지 않고 생략가능합니다. 다만 필요하다면 미지의 경우를 처리하기 위해 포함해야 합니다.</p> +</div> + +<h3 id="A_switch_example">A switch example</h3> + +<p>실전 예제를 해봅시다.switch문을 활용해 일기예보 애플리케이션을 작성하세요.</p> + +<pre class="brush: html notranslate"><label for="weather">Select the weather type today: </label> +<select id="weather"> + <option value="">--Make a choice--</option> + <option value="sunny">Sunny</option> + <option value="rainy">Rainy</option> + <option value="snowing">Snowing</option> + <option value="overcast">Overcast</option> +</select> + +<p></p></pre> + +<pre class="brush: js notranslate">var select = document.querySelector('select'); +var para = document.querySelector('p'); + +select.addEventListener('change', setWeather); + + +function setWeather() { + var choice = select.value; + + switch (choice) { + case 'sunny': + para.textContent = 'It is nice and sunny outside today. Wear shorts! Go to the beach, or the park, and get an ice cream.'; + break; + case 'rainy': + para.textContent = 'Rain is falling outside; take a rain coat and a brolly, and don\'t stay out for too long.'; + break; + case 'snowing': + para.textContent = 'The snow is coming down — it is freezing! Best to stay in with a cup of hot chocolate, or go build a snowman.'; + break; + case 'overcast': + para.textContent = 'It isn\'t raining, but the sky is grey and gloomy; it could turn any minute, so take a rain coat just in case.'; + break; + default: + para.textContent = ''; + } +}</pre> + +<p>{{ EmbedLiveSample('A_switch_example', '100%', 100, "", "", "hide-codepen-jsfiddle") }}</p> + +<div class="note"> +<p><strong>Note</strong>: You can also <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/simple-switch.html">find this example on GitHub</a> (see it <a href="http://mdn.github.io/learning-area/javascript/building-blocks/simple-switch.html">running live</a> on there also.)</p> +</div> + +<h2 id="삼항연산자">삼항연산자 </h2> + +<p>다른 예제로 들어가기 전에 소개하고 싶은 마지막 구문이 있다.삼항(조건)연산자( <a href="/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator">ternary or conditional operator</a>)는 조건이 참이면 한 값/표현식을 반환하고 조건이 거짓이면 다른 값/표현식을 반환하는 구문이다.— 이것은 어떤 상황에 유용할 수 있으며, 참/거짓 조건을 간단히 선택할 수 있는 상황이라면 <code>if...else</code> 블록문보다 코드를 훨씬 적게 사용할수 있다. 이 pseudocode는 아래와 같다:</p> + +<pre class="notranslate">( condition ) ? run this code : run this code instead</pre> + +<p>그러면 간단한 예를 보자:</p> + +<pre class="brush: js notranslate">var greeting = ( isBirthday ) ? 'Happy birthday Mrs. Smith — we hope you have a great day!' : 'Good morning Mrs. Smith.';</pre> + +<p><code>isBirthday</code> 라는 변수명이 여기 있다— 게스트가 생일이면 '해피버스데이' 메세지를 보내고, 생일이 아니라면 일반적인 '인사' 메세지를 보내는 경우에 해당된다..</p> + +<h3 id="삼항_연산자_예제">삼항 연산자 예제</h3> + +<p>삼항연산자로 변수값을 정할 필요가 없다; 단지 좋아하는 함수나 코드를 사용하면 된다. — . 이 예제는 삼항연산자를 사용하여 사이트의 스타일링 테마를 선택할 수 있는 것을 보여준다</p> + +<pre class="brush: html notranslate"><label for="theme">Select theme: </label> +<select id="theme"> + <option value="white">White</option> + <option value="black">Black</option> +</select> + +<h1>This is my website</h1></pre> + +<pre class="brush: js notranslate">var select = document.querySelector('select'); +var html = document.querySelector('html'); +document.body.style.padding = '10px'; + +function update(bgColor, textColor) { + html.style.backgroundColor = bgColor; + html.style.color = textColor; +} + +select.onchange = function() { + ( select.value === 'black' ) ? update('black','white') : update('white','black'); +} +</pre> + +<p>{{ EmbedLiveSample('Ternary_operator_example', '100%', 300, "", "", "hide-codepen-jsfiddle") }}</p> + +<p>여기에는 black이나 white의 테마를 고르기 위한 '{{htmlelement('select')}}' 엘리먼트가 있고, 여기에 더하여 웹사이트 제목을 보여주는 '{{htmlelement('h1')}}" 엘리먼트가 있다. <code>update()</code> 함수를 덧붙이면 두 칼라를 입력 인수(parameter)로 선택할 수 있다. 웹사이트 배경 칼라가 첫 번째 칼라로 지정되고, 텍스트 칼라가 두 번째로 정해진다.</p> + +<p>끝으로, '<a href="/en-US/docs/Web/API/GlobalEventHandlers/onchange">onchange</a>' 이벤트 리스너는 삼중연산자를 포함하는 함수를 움직('run')이게 합니다. <code>select.value === 'black' </code>조건을 테스트는 하는 것으로 시작하는데, 이 조건이 참이면 <code>update()</code> 함수가 배경색은 black으로 텍스트 색은 white로 동작하게 합니다. 이와는 반대로 select theme이 white로 선택되면(조건이 거짓이면) , <code>update()</code> 함수는 배경색은 white으로 텍스트 색은 black로 동작하게 합니다.</p> + +<div class="note"> +<p><strong>Note</strong>: You can also <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/simple-ternary.html">find this example on GitHub</a> (see it <a href="http://mdn.github.io/learning-area/javascript/building-blocks/simple-ternary.html">running live</a> on there also.)</p> +</div> + +<h2 id="Active_learning_간단한_달력_만들기">Active learning: 간단한 달력 만들기</h2> + +<p>이 예제에서는 간단한 달력 어플리케이션을 만들어 볼겁니다. 코드에는 다음과 같은 것들이 들어 있습니다.</p> + +<ul> + <li>유저가 여러 달 중 특정 달을 고를 수 있게 하는 {{htmlelement("select")}} 요소.</li> + <li><code><select></code> 메뉴에서 선택된 값이 변경 되었음을 탐지하는 <code>onchange</code> 이벤트 핸들러.</li> + <li>{{htmlelement("h1")}} 요소에서 달력을 생성하고 올바른 달을 표시하는 <code>createCalendar()</code> 함수.</li> +</ul> + +<p><code>onchange</code> 핸들러 함수내에 조건문을 작성해야 합니다. 위치는 <code>// ADD CONDITIONAL HERE</code> 주석 바로 아래입니다. 조건문은 다음을 만족해야 합니다:</p> + +<ol> + <li>선택한 달 보기(이것은 값이 변경된 후의 요소 값이 됨.) </li> + <li><code>days</code> 란 변수를 선택한 달의 일 수와 같게 하기. 다만 윤년은 무시할 수 있다.</li> +</ol> + +<p>Hints:</p> + +<ul> + <li>논리연산자 OR을 사용해 동일한 일 수인 여러 달을 하나의 조건으로 그룹화 하기.</li> + <li>가장 흔한 일 수를 기본값을 사용하기.</li> +</ul> + +<p>만약 실수를 하더라도 'Reset' 버튼으로 초기화 할 수 있습니다. 해답을 모르겠다면 "Show solution" 으로 해결방법을 확인하세요.</p> + +<div class="hidden"> +<h6 id="Playable_code">Playable code</h6> + +<pre class="brush: html notranslate"><h2>Live output</h2> +<div class="output" style="height: 500px;overflow: auto;"> + <label for="month">Select month: </label> + <select id="month"> + <option value="January">January</option> + <option value="February">February</option> + <option value="March">March</option> + <option value="April">April</option> + <option value="May">May</option> + <option value="June">June</option> + <option value="July">July</option> + <option value="August">August</option> + <option value="September">September</option> + <option value="October">October</option> + <option value="November">November</option> + <option value="December">December</option> + </select> + + <h1></h1> + + <ul></ul> +</div> + +<h2>Editable code</h2> +<p class="a11y-label">Press Esc to move focus away from the code area (Tab inserts a tab character).</p> + +<textarea id="code" class="playable-code" style="height: 400px;width: 95%"> +var select = document.querySelector('select'); +var list = document.querySelector('ul'); +var h1 = document.querySelector('h1'); + +select.onchange = function() { + var choice = select.value; + + // ADD CONDITIONAL HERE + + createCalendar(days, choice); +} + +function createCalendar(days, choice) { + list.innerHTML = ''; + h1.textContent = choice; + for (var i = 1; i <= days; i++) { + var listItem = document.createElement('li'); + listItem.textContent = i; + list.appendChild(listItem); + } +} + +createCalendar(31,'January'); +</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Reset"> + <input id="solution" type="button" value="Show solution"> +</div> +</pre> + +<pre class="brush: css notranslate">.output * { + box-sizing: border-box; +} + +.output ul { + padding-left: 0; +} + +.output li { + display: block; + float: left; + width: 25%; + border: 2px solid white; + padding: 5px; + height: 40px; + background-color: #4A2DB6; + color: white; +} + +html { + font-family: sans-serif; +} + +h2 { + font-size: 16px; +} + +.a11y-label { + margin: 0; + text-align: right; + font-size: 0.7rem; + width: 98%; +} + +body { + margin: 10px; + background: #f5f9fa; +}</pre> + +<pre class="brush: js notranslate">var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var code = textarea.value; +var userEntry = textarea.value; + +function updateCode() { + eval(textarea.value); +} + +reset.addEventListener('click', function() { + textarea.value = code; + userEntry = textarea.value; + solutionEntry = jsSolution; + solution.value = 'Show solution'; + updateCode(); +}); + +solution.addEventListener('click', function() { + if(solution.value === 'Show solution') { + textarea.value = solutionEntry; + solution.value = 'Hide solution'; + } else { + textarea.value = userEntry; + solution.value = 'Show solution'; + } + updateCode(); +}); + +var jsSolution = 'var select = document.querySelector(\'select\');\nvar list = document.querySelector(\'ul\');\nvar h1 = document.querySelector(\'h1\');\n\nselect.onchange = function() {\n var choice = select.value;\n var days = 31;\n if(choice === \'February\') {\n days = 28;\n } else if(choice === \'April\' || choice === \'June\' || choice === \'September\'|| choice === \'November\') {\n days = 30;\n }\n\n createCalendar(days, choice);\n}\n\nfunction createCalendar(days, choice) {\n list.innerHTML = \'\';\n h1.textContent = choice;\n for(var i = 1; i <= days; i++) {\n var listItem = document.createElement(\'li\');\n listItem.textContent = i;\n list.appendChild(listItem);\n }\n }\n\ncreateCalendar(31,\'January\');'; +var solutionEntry = jsSolution; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); + +// stop tab key tabbing out of textarea and +// make it write a tab at the caret position instead + +textarea.onkeydown = function(e){ + if (e.keyCode === 9) { + e.preventDefault(); + insertAtCaret('\t'); + } + + if (e.keyCode === 27) { + textarea.blur(); + } +}; + +function insertAtCaret(text) { + var scrollPos = textarea.scrollTop; + var caretPos = textarea.selectionStart; + + var front = (textarea.value).substring(0, caretPos); + var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length); + textarea.value = front + text + back; + caretPos = caretPos + text.length; + textarea.selectionStart = caretPos; + textarea.selectionEnd = caretPos; + textarea.focus(); + textarea.scrollTop = scrollPos; +} + +// Update the saved userCode every time the user updates the text area code + +textarea.onkeyup = function(){ + // We only want to save the state when the user code is being shown, + // not the solution, so that solution is not saved over the user code + if(solution.value === 'Show solution') { + userEntry = textarea.value; + } else { + solutionEntry = textarea.value; + } + + updateCode(); +};</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code', '100%', 1110, "", "", "hide-codepen-jsfiddle") }}</p> + +<h2 id="Active_learning_색깔_고르기">Active learning: 색깔 고르기</h2> + +<p>In this example you are going to take the ternary operator example we saw earlier and convert the ternary operator into a switch statement that will allow us to apply more choices to the simple website. Look at the {{htmlelement("select")}} — this time you'll see that it has not two theme options, but five. You need to add a switch statement just underneath the <code>// ADD SWITCH STATEMENT</code> comment:</p> + +<ul> + <li>It should accept the <code>choice</code> variable as its input expression.</li> + <li>For each case, the choice should equal one of the possible values that can be selected, i.e. white, black, purple, yellow, or psychedelic.</li> + <li>For each case, the <code>update()</code> function should be run, and be passed two color values, the first one for the background color, and the second one for the text color. Remember that color values are strings, so need to be wrapped in quotes.</li> +</ul> + +<p>If you make a mistake, you can always reset the example with the "Reset" button. If you get really stuck, press "Show solution" to see a solution.</p> + +<div class="hidden"> +<h6 id="Playable_code_2">Playable code 2</h6> + +<pre class="brush: html notranslate"><h2>Live output</h2> +<div class="output" style="height: 300px;"> + <label for="theme">Select theme: </label> + <select id="theme"> + <option value="white">White</option> + <option value="black">Black</option> + <option value="purple">Purple</option> + <option value="yellow">Yellow</option> + <option value="psychedelic">Psychedelic</option> + </select> + + <h1>This is my website</h1> +</div> + +<h2>Editable code</h2> +<p class="a11y-label">Press Esc to move focus away from the code area (Tab inserts a tab character).</p> + +<textarea id="code" class="playable-code" style="height: 450px;width: 95%"> +var select = document.querySelector('select'); +var html = document.querySelector('.output'); + +select.onchange = function() { + var choice = select.value; + + // ADD SWITCH STATEMENT +} + +function update(bgColor, textColor) { + html.style.backgroundColor = bgColor; + html.style.color = textColor; +}</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Reset"> + <input id="solution" type="button" value="Show solution"> +</div> +</pre> + +<pre class="brush: css notranslate">html { + font-family: sans-serif; +} + +h2 { + font-size: 16px; +} + +.a11y-label { + margin: 0; + text-align: right; + font-size: 0.7rem; + width: 98%; +} + +body { + margin: 10px; + background: #f5f9fa; +}</pre> + +<pre class="brush: js notranslate">var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var code = textarea.value; +var userEntry = textarea.value; + +function updateCode() { + eval(textarea.value); +} + +reset.addEventListener('click', function() { + textarea.value = code; + userEntry = textarea.value; + solutionEntry = jsSolution; + solution.value = 'Show solution'; + updateCode(); +}); + +solution.addEventListener('click', function() { + if(solution.value === 'Show solution') { + textarea.value = solutionEntry; + solution.value = 'Hide solution'; + } else { + textarea.value = userEntry; + solution.value = 'Show solution'; + } + updateCode(); +}); + +var jsSolution = 'var select = document.querySelector(\'select\');\nvar html = document.querySelector(\'.output\');\n\nselect.onchange = function() {\n var choice = select.value;\n\n switch(choice) {\n case \'black\':\n update(\'black\',\'white\');\n break;\n case \'white\':\n update(\'white\',\'black\');\n break;\n case \'purple\':\n update(\'purple\',\'white\');\n break;\n case \'yellow\':\n update(\'yellow\',\'darkgray\');\n break;\n case \'psychedelic\':\n update(\'lime\',\'purple\');\n break;\n }\n}\n\nfunction update(bgColor, textColor) {\n html.style.backgroundColor = bgColor;\n html.style.color = textColor;\n}'; +var solutionEntry = jsSolution; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); + +// stop tab key tabbing out of textarea and +// make it write a tab at the caret position instead + +textarea.onkeydown = function(e){ + if (e.keyCode === 9) { + e.preventDefault(); + insertAtCaret('\t'); + } + + if (e.keyCode === 27) { + textarea.blur(); + } +}; + +function insertAtCaret(text) { + var scrollPos = textarea.scrollTop; + var caretPos = textarea.selectionStart; + + var front = (textarea.value).substring(0, caretPos); + var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length); + textarea.value = front + text + back; + caretPos = caretPos + text.length; + textarea.selectionStart = caretPos; + textarea.selectionEnd = caretPos; + textarea.focus(); + textarea.scrollTop = scrollPos; +} + +// Update the saved userCode every time the user updates the text area code + +textarea.onkeyup = function(){ + // We only want to save the state when the user code is being shown, + // not the solution, so that solution is not saved over the user code + if(solution.value === 'Show solution') { + userEntry = textarea.value; + } else { + solutionEntry = textarea.value; + } + + updateCode(); +};</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code_2', '100%', 950, "", "", "hide-codepen-jsfiddle") }}</p> + +<h2 id="Conclusion">Conclusion</h2> + +<p>And that's all you really need to know about conditional structures in JavaScript right now! I'm sure you'll have understood these concepts and worked through the examples with ease; if there is anything you didn't understand, feel free to read through the article again, or <a href="/en-US/Learn#Contact_us">contact us</a> to ask for help.</p> + +<h2 id="See_also">See also</h2> + +<ul> + <li><a href="/en-US/Learn/JavaScript/First_steps/Math#Comparison_operators">Comparison operators</a></li> + <li><a href="/en-US/docs/Web/JavaScript/Guide/Control_flow_and_error_handling#Conditional_statements">Conditional statements in detail</a></li> + <li><a href="/en-US/docs/Web/JavaScript/Reference/Statements/if...else">if...else reference</a></li> + <li><a href="/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator">Conditional (ternary) operator reference</a></li> +</ul> + +<p>{{NextMenu("Learn/JavaScript/Building_blocks/Looping_code", "Learn/JavaScript/Building_blocks")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/conditionals">Making decisions in your code — conditionals</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Looping_code">Looping code</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions">Functions — reusable blocks of code</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Build_your_own_function">Build your own function</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Return_values">Function return values</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events">Introduction to events</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Image_gallery">Image gallery</a></li> +</ul> diff --git a/files/ko/learn/javascript/client-side_web_apis/client-side_storage/index.html b/files/ko/learn/javascript/client-side_web_apis/client-side_storage/index.html new file mode 100644 index 0000000000..e2ac144050 --- /dev/null +++ b/files/ko/learn/javascript/client-side_web_apis/client-side_storage/index.html @@ -0,0 +1,780 @@ +--- +title: Client-side storage +slug: Learn/JavaScript/Client-side_web_APIs/Client-side_storage +translation_of: Learn/JavaScript/Client-side_web_APIs/Client-side_storage +--- +<p>{{LearnSidebar}}</p> + +<div>{{PreviousMenu("Learn/JavaScript/Client-side_web_APIs/Video_and_audio_APIs", "Learn/JavaScript/Client-side_web_APIs")}}</div> + +<div></div> + +<p class="summary">현대 웹 브라우저들은 (사용자의 허락 하에) 사용자 컴퓨터에 웹사이트 정보를 저장할 수 있는 다양한 방법을 제공합니다. 그리고 필요한때 그 정보들을 읽어오죠. 이는 당신이 장기간 데이터를 보관할 수 있게 해주고 사이트와 웹문서를 당신이 지정한 설정에 따라 오프라인 상태에서도 사용할수 있게 해줍니다. 이 문서는 이러한 것들이 어떻게 동작하는지에 대한 기본지식들을 설명합니다. </p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Prerequisites:</th> + <td>JavaScript basics (see <a href="/en-US/docs/Learn/JavaScript/First_steps">first steps</a>, <a href="/en-US/docs/Learn/JavaScript/Building_blocks">building blocks</a>, <a href="/en-US/docs/Learn/JavaScript/Objects">JavaScript objects</a>), the <a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Introduction">basics of Client-side APIs</a></td> + </tr> + <tr> + <th scope="row">Objective:</th> + <td>To learn how to use client-side storage APIs to store application data.</td> + </tr> + </tbody> +</table> + +<h2 id="Client-side_storage">Client-side storage?</h2> + +<p>우리는 다른 MDN 학습영역에서 <a href="/en-US/docs/Learn/Server-side/First_steps/Client-Server_overview#Static_sites">정적인 사이트</a>와 <a href="/en-US/docs/Learn/Server-side/First_steps/Client-Server_overview#Dynamic_sites">동적인 사이트</a>에 대해 이미 설명하였습니다. 현대의 대부분의 웹사이트들은 어떤 데이터베이스(서버의 저장소)를 이용하여 서버에 데이터를 저장하고, 필요한 데이터를 찾아오기 위해 <a href="/en-US/docs/Learn/Server-side">서버-사이드</a> 코드를 돌리고, 정적인 페이지 템플릿에 데이터를 삽입하고, HTML 결과물을 사용자의 브라우저에 표시될 수 있게 제공합니다 - 즉 동적입니다.</p> + +<p>클라이언트-사이드 저장소는 비슷한 원리로 작동하지만, 다르게 쓰입니다. 이것은 개발자가 클라이언트 측(사용자의 컴퓨터 등)에 데이터를 저장할 수 있고 필요할 때 가져올 수 있게 해주는 자바스크립트 API로 구성되어 있습니다. 이것의 다양한 용도는 다음과 같습니다.</p> + +<ul> + <li>웹사이트에 대한 선호를 개인화하기(사용자가 선택한 커스텀 위젯, 배색, 폰트 크기로 보여주기)</li> + <li>이전 활동 기록 저장하기(이전 세션에 담았던 장바구니 목록 저장하기, 로그인 유지하기)</li> + <li>사이트 다운로드가 빨라지고(잠재적으로 비용이 적게 들어가고) 네트워크 연결 없이도 사용할 수 있게끔 데이터를 로컬에 저장하기</li> + <li>오프라인 상태에서 사용할 수 있도록 웹 어플리케이션 생성 문서를 로컬에 저장하기</li> +</ul> + +<p>클라이언트-사이드 저장소와 서버-사이드 저장소는 대개 함께 사용됩니다. 예를 들면, 당신은 (아마도 웹 게임이나 음악 재생 어플리케이션에서 사용할)음악 파일 여러 개를 다운받아 클라이언트-사이드 데이터베이스에 저장하고 필요할 때 재생할 수 있습니다. 사용자는 음악 파일을 한번만 다운받고, 재방문 시에는 데이터베이스에서 가져오기만 하면 됩니다.</p> + +<div class="note"> +<p><strong>Note</strong>: There are limits to the amount of data you can store using client-side storage APIs (possibly both per individual API and cumulatively); the exact limit varies depending on the browser and possibly based on user settings. See <a href="/en-US/docs/Web/API/IndexedDB_API/Browser_storage_limits_and_eviction_criteria">Browser storage limits and eviction criteria</a> for more information.</p> +</div> + +<h3 id="Old_fashioned_cookies">Old fashioned: cookies</h3> + +<p>클라이언트-사이드 저장소에 대한 개념은 오래전부터 있었습니다. 웹의 태동기 시절, 웹 사이트들은 사용자 경험(UX)을 개인화하는 정보들을 저장하기 위해 <a href="/en-US/docs/Web/HTTP/Cookies">cookies</a>를 사용했습니다. 그것들이 웹에서 보편적으로 사용된 클라이언트-사이드 저장소의 제일 오래된 형태입니다.</p> + +<p>오늘날에는 클라이언트 사이드에 데이터를 저장하는 더 쉬운 방법이 있지만, 이 문서에서 cookies를 사용하는 법을 가르쳐 주지는 않습니다. 그러나, 이것이 현대의 웹에서 cookies가 완벽하게 쓸모없다는 것을 뜻하지는 않습니다. cookies는 세션 ID나 access token 같은 사용자 상태와 개인화에 관련된 정보를 저장하는데 여전히 보편적으로 쓰입니다. cookies에 대한 더 자세한 정보는 우리의 <a href="/en-US/docs/Web/HTTP/Cookies">Using HTTP cookies</a> 문서를 참고하세요.</p> + +<h3 id="New_school_Web_Storage_and_IndexedDB">New school: Web Storage and IndexedDB</h3> + +<p>현대의 브라우저들은 클라이언트-사이드 데이터를 저장하는 데에 cookies보다 더 쉽고 더 효율적인 API들을 제공합니다.</p> + +<ul> + <li><a href="/en-US/docs/Web/API/Web_Storage_API">Web Storage API</a>는 이름과 대응되는 값으로 이루어진 더 작은 데이터를 저장하고 가져오는 매우 간단한 기능을 제공합니다. 이것은 사용자 이름과 로그인 여부, 스크린 배경색을 어떤 색으로 할지 등등 같은 간단한 데이터를 저장할 필요가 있을 때 유용합니다. </li> + <li><a href="/en-US/docs/Web/API/IndexedDB_API">IndexedDB API</a>는 복잡한 데이터를 저장할 수 있는 완벽한 데이터베이스를 브라우저에서 제공할 수 있게 해줍니다. 이것은 소비자 기록의 복잡한 데이터셋부터 오디오나 비디오 파일같은 더욱 복잡한 데이터까지 저장하는 데에 쓰일 수 있습니다.</li> +</ul> + +<p>밑에서 이런 API들을 더 배울 수 있습니다.</p> + +<h3 id="The_future_Cache_API">The future: Cache API</h3> + +<p>몇몇 현대적인 브라우저들은 새로운 {{domxref("Cache")}} API를 제공합니다. 이 API는 특정 requests에 대한 HTTP responses를 저장하기 위해 디자인되었고, 웹사이트가 차후에 네트워크 연결 없이도 사용될 수 있도록 사이트 정보를 저장하는 등의 일을 하는데 유용합니다. Cache는 일반적으로 <a href="/en-US/docs/Web/API/Service_Worker_API">Service Worker API</a>와 함께 사용되지만, 꼭 그럴 필요는 없습니다.</p> + +<p>Cache와 Service Workers의 사용은 심화 주제이므로 이 문서에서는 아래의 {{anch("Offline asset storage")}} 섹션에서 보여주는 것 이상으로 깊게 다루지는 않을 것입니다.</p> + +<h2 id="Storing_simple_data_—_web_storage">Storing simple data — web storage</h2> + +<p>The <a href="/en-US/docs/Web/API/Web_Storage_API">Web Storage API</a> is very easy to use — you store simple name/value pairs of data (limited to strings, numbers, etc.) and retrieve these values when needed.</p> + +<h3 id="Basic_syntax">Basic syntax</h3> + +<p>Let's show you how:</p> + +<ol> + <li> + <p>First, go to our <a href="https://mdn.github.io/learning-area/javascript/apis/client-side-storage/web-storage/index.html">web storage blank template</a> on GitHub (open this in a new tab).</p> + </li> + <li> + <p>Open the JavaScript console of your browser's developer tools.</p> + </li> + <li> + <p>All of your web storage data is contained within two object-like structures inside the browser: {{domxref("Window.sessionStorage", "sessionStorage")}} and {{domxref("Window.localStorage", "localStorage")}}. The first one persists data for as long as the browser is open (the data is lost when the browser is closed) and the second one persists data even after the browser is closed and then opened again. We'll use the second one in this article as it is generally more useful.</p> + + <p>The {{domxref("Storage.setItem()")}} method allows you to save a data item in storage — it takes two parameters: the name of the item, and its value. Try typing this into your JavaScript console (change the value to your own name, if you wish!):</p> + + <pre class="brush: js notranslate">localStorage.setItem('name','Chris');</pre> + </li> + <li> + <p>The {{domxref("Storage.getItem()")}} method takes one parameter — the name of a data item you want to retrieve — and returns the item's value. Now type these lines into your JavaScript console:</p> + + <pre class="brush: js notranslate">var myName = localStorage.getItem('name'); +myName</pre> + + <p>Upon typing in the second line, you should see that the <code>myName</code> variable now contains the value of the <code>name</code> data item.</p> + </li> + <li> + <p>The {{domxref("Storage.removeItem()")}} method takes one parameter — the name of a data item you want to remove — and removes that item out of web storage. Type the following lines into your JavaScript console:</p> + + <pre class="brush: js notranslate">localStorage.removeItem('name'); +var myName = localStorage.getItem('name'); +myName</pre> + + <p>The third line should now return <code>null</code> — the <code>name</code> item no longer exists in the web storage.</p> + </li> +</ol> + +<h3 id="The_data_persists!">The data persists!</h3> + +<p>One key feature of web storage is that the data persists between page loads (and even when the browser is shut down, in the case of <code>localStorage</code>). Let's look at this in action.</p> + +<ol> + <li> + <p>Open our web storage blank template again, but this time in a different browser to the one you've got this tutorial open in! This will make it easier to deal with.</p> + </li> + <li> + <p>Type these lines into the browser's JavaScript console:</p> + + <pre class="brush: js notranslate">localStorage.setItem('name','Chris'); +var myName = localStorage.getItem('name'); +myName</pre> + + <p>You should see the name item returned.</p> + </li> + <li> + <p>Now close down the browser and open it up again.</p> + </li> + <li> + <p>Enter the following lines again:</p> + + <pre class="brush: js notranslate">var myName = localStorage.getItem('name'); +myName</pre> + + <p>You should see that the value is still available, even though the browser has been closed and then opened again.</p> + </li> +</ol> + +<h3 id="Separate_storage_for_each_domain">Separate storage for each domain</h3> + +<p>There is a separate data store for each domain (each separate web address loaded in the browser). You will see that if you load two websites (say google.com and amazon.com) and try storing an item on one website, it won't be available to the other website.</p> + +<p>This makes sense — you can imagine the security issues that would arise if websites could see each other's data!</p> + +<h3 id="A_more_involved_example">A more involved example</h3> + +<p>Let's apply this new-found knowledge by writing a simple working example to give you an idea of how web storage can be used. Our example will allow you enter a name, after which the page will update to give you a personalized greeting. This state will also persist across page/browser reloads, because the name is stored in web storage.</p> + +<p>You can find the example HTML at <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/client-side-storage/web-storage/personal-greeting.html">personal-greeting.html</a> — this contains a simple website with a header, content, and footer, and a form for entering your name.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/15735/web-storage-demo.png" style="display: block; margin: 0 auto;"></p> + +<p>Let's build up the example, so you can understand how it works.</p> + +<ol> + <li> + <p>First, make a local copy of our <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/client-side-storage/web-storage/personal-greeting.html">personal-greeting.html</a> file in a new directory on your computer.</p> + </li> + <li> + <p>Next, note how our HTML references a JavaScript file called <code>index.js</code> (see line 40). We need to create this and write our JavaScript code into it. Create an <code>index.js</code> file in the same directory as your HTML file. </p> + </li> + <li> + <p>We'll start off by creating references to all the HTML features we need to manipulate in this example — we'll create them all as constants, as these references do not need to change in the lifecycle of the app. Add the following lines to your JavaScript file:</p> + + <pre class="brush: js notranslate">// create needed constants +const rememberDiv = document.querySelector('.remember'); +const forgetDiv = document.querySelector('.forget'); +const form = document.querySelector('form'); +const nameInput = document.querySelector('#entername'); +const submitBtn = document.querySelector('#submitname'); +const forgetBtn = document.querySelector('#forgetname'); + +const h1 = document.querySelector('h1'); +const personalGreeting = document.querySelector('.personal-greeting');</pre> + </li> + <li> + <p>Next up, we need to include a small event listener to stop the form from actually submitting itself when the submit button is pressed, as this is not the behavior we want. Add this snippet below your previous code:</p> + + <pre class="brush: js notranslate">// Stop the form from submitting when a button is pressed +form.addEventListener('submit', function(e) { + e.preventDefault(); +});</pre> + </li> + <li> + <p>Now we need to add an event listener, the handler function of which will run when the "Say hello" button is clicked. The comments explain in detail what each bit does, but in essence here we are taking the name the user has entered into the text input box and saving it in web storage using <code>setItem()</code>, then running a function called <code>nameDisplayCheck()</code> that will handle updating the actual website text. Add this to the bottom of your code:</p> + + <pre class="brush: js notranslate">// run function when the 'Say hello' button is clicked +submitBtn.addEventListener('click', function() { + // store the entered name in web storage + localStorage.setItem('name', nameInput.value); + // run nameDisplayCheck() to sort out displaying the + // personalized greetings and updating the form display + nameDisplayCheck(); +});</pre> + </li> + <li> + <p>At this point we also need an event handler to run a function when the "Forget" button is clicked — this is only displayed after the "Say hello" button has been clicked (the two form states toggle back and forth). In this function we remove the <code>name</code> item from web storage using <code>removeItem()</code>, then again run <code>nameDisplayCheck()</code> to update the display. Add this to the bottom:</p> + + <pre class="brush: js notranslate">// run function when the 'Forget' button is clicked +forgetBtn.addEventListener('click', function() { + // Remove the stored name from web storage + localStorage.removeItem('name'); + // run nameDisplayCheck() to sort out displaying the + // generic greeting again and updating the form display + nameDisplayCheck(); +});</pre> + </li> + <li> + <p>It is now time to define the <code>nameDisplayCheck()</code> function itself. Here we check whether the name item has been stored in web storage by using <code>localStorage.getItem('name')</code> as a conditional test. If it has been stored, this call will evaluate to <code>true</code>; if not, it will be <code>false</code>. If it is <code>true</code>, we display a personalized greeting, display the "forget" part of the form, and hide the "Say hello" part of the form. If it is <code>false</code>, we display a generic greeting and do the opposite. Again, put the following code at the bottom:</p> + + <pre class="brush: js notranslate">// define the nameDisplayCheck() function +function nameDisplayCheck() { + // check whether the 'name' data item is stored in web Storage + if(localStorage.getItem('name')) { + // If it is, display personalized greeting + let name = localStorage.getItem('name'); + h1.textContent = 'Welcome, ' + name; + personalGreeting.textContent = 'Welcome to our website, ' + name + '! We hope you have fun while you are here.'; + // hide the 'remember' part of the form and show the 'forget' part + forgetDiv.style.display = 'block'; + rememberDiv.style.display = 'none'; + } else { + // if not, display generic greeting + h1.textContent = 'Welcome to our website '; + personalGreeting.textContent = 'Welcome to our website. We hope you have fun while you are here.'; + // hide the 'forget' part of the form and show the 'remember' part + forgetDiv.style.display = 'none'; + rememberDiv.style.display = 'block'; + } +}</pre> + </li> + <li> + <p>Last but not least, we need to run the <code>nameDisplayCheck()</code> function every time the page is loaded. If we don't do this, then the personalized greeting will not persist across page reloads. Add the following to the bottom of your code:</p> + + <pre class="brush: js notranslate">document.body.onload = nameDisplayCheck;</pre> + </li> +</ol> + +<p>Your example is finished — well done! All that remains now is to save your code and test your HTML page in a browser. You can see our <a href="https://mdn.github.io/learning-area/javascript/apis/client-side-storage/web-storage/personal-greeting.html">finished version running live here</a>.</p> + +<div class="note"> +<p><strong>Note</strong>: There is another, slightly more complex example to explore at <a href="/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API">Using the Web Storage API</a>.</p> +</div> + +<div class="note"> +<p><strong>Note</strong>: In the line <code><script src="index.js" defer></script></code> of the source for our finished version, the <code>defer</code> attribute specifies that the contents of the {{htmlelement("script")}} element will not execute until the page has finished loading.</p> +</div> + +<h2 id="Storing_complex_data_—_IndexedDB">Storing complex data — IndexedDB</h2> + +<p>The <a href="/en-US/docs/Web/API/IndexedDB_API">IndexedDB API</a> (sometimes abbreviated IDB) is a complete database system available in the browser in which you can store complex related data, the types of which aren't limited to simple values like strings or numbers. You can store videos, images, and pretty much anything else in an IndexedDB instance.</p> + +<p>However, this does come at a cost: IndexedDB is much more complex to use than the Web Storage API. In this section, we'll really only scratch the surface of what it is capable of, but we will give you enough to get started.</p> + +<h3 id="Working_through_a_note_storage_example">Working through a note storage example</h3> + +<p>Here we'll run you through an example that allows you to store notes in your browser and view and delete them whenever you like, getting you to build it up for yourself and explaining the most fundamental parts of IDB as we go along.</p> + +<p>The app looks something like this:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/15744/idb-demo.png" style="border-style: solid; border-width: 1px; display: block; margin: 0px auto;"></p> + +<p>Each note has a title and some body text, each individually editable. The JavaScript code we'll go through below has detailed comments to help you understand what's going on.</p> + +<h3 id="Getting_started">Getting started</h3> + +<ol> + <li>First of all, make local copies of our <code><a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/client-side-storage/indexeddb/notes/index.html">index.html</a></code>, <code><a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/client-side-storage/indexeddb/notes/style.css">style.css</a></code>, and <code><a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/client-side-storage/indexeddb/notes/index-start.js">index-start.js</a></code> files into a new directory on your local machine.</li> + <li>Have a look at the files. You'll see that the HTML is pretty simple: a web site with a header and footer, as well as a main content area that contains a place to display notes, and a form for entering new notes into the database. The CSS provides some simple styling to make it clearer what is going on. The JavaScript file contains five declared constants containing references to the {{htmlelement("ul")}} element the notes will be displayed in, the title and body {{htmlelement("input")}} elements, the {{htmlelement("form")}} itself, and the {{htmlelement("button")}}.</li> + <li>Rename your JavaScript file to <code>index.js</code>. You are now ready to start adding code to it.</li> +</ol> + +<h3 id="Database_initial_set_up">Database initial set up</h3> + +<p>Now let's look at what we have to do in the first place, to actually set up a database.</p> + +<ol> + <li> + <p>Below the constant declarations, add the following lines:</p> + + <pre class="brush: js notranslate">// Create an instance of a db object for us to store the open database in +let db;</pre> + + <p>Here we are declaring a variable called <code>db</code> — this will later be used to store an object representing our database. We will use this in a few places, so we've declared it globally here to make things easier.</p> + </li> + <li> + <p>Next, add the following to the bottom of your code:</p> + + <pre class="brush: js notranslate">window.onload = function() { + +};</pre> + + <p>We will write all of our subsequent code inside this <code>window.onload</code> event handler function, called when the window's {{event("load")}} event fires, to make sure we don't try to use IndexedDB functionality before the app has completely finished loading (it could fail if we don't).</p> + </li> + <li> + <p>Inside the <code>window.onload</code> handler, add the following:</p> + + <pre class="brush: js notranslate">// Open our database; it is created if it doesn't already exist +// (see onupgradeneeded below) +let request = window.indexedDB.open('notes_db', 1);</pre> + + <p>This line creates a <code>request</code> to open version <code>1</code> of a database called <code>notes_db</code>. If this doesn't already exist, it will be created for you by subsequent code. You will see this request pattern used very often throughout IndexedDB. Database operations take time. You don't want to hang the browser while you wait for the results, so database operations are {{Glossary("asynchronous")}}, meaning that instead of happening immediately, they will happen at some point in the future, and you get notified when they're done.</p> + + <p>To handle this in IndexedDB, you create a request object (which can be called anything you like — we called it <code>request</code> so it is obvious what it is for). You then use event handlers to run code when the request completes, fails, etc., which you'll see in use below.</p> + + <div class="note"> + <p><strong>Note</strong>: The version number is important. If you want to upgrade your database (for example, by changing the table structure), you have to run your code again with an increased version number, different schema specified inside the <code>onupgradeneeded</code> handler (see below), etc. We won't cover upgrading databases in this simple tutorial.</p> + </div> + </li> + <li> + <p>Now add the following event handlers just below your previous addition — again inside the <code>window.onload</code> handler:</p> + + <pre class="brush: js notranslate">// onerror handler signifies that the database didn't open successfully +request.onerror = function() { + console.log('Database failed to open'); +}; + +// onsuccess handler signifies that the database opened successfully +request.onsuccess = function() { + console.log('Database opened successfully'); + + // Store the opened database object in the db variable. This is used a lot below + db = request.result; + + // Run the displayData() function to display the notes already in the IDB + displayData(); +};</pre> + + <p>The {{domxref("IDBRequest.onerror", "request.onerror")}} handler will run if the system comes back saying that the request failed. This allows you to respond to this problem. In our simple example, we just print a message to the JavaScript console.</p> + + <p>The {{domxref("IDBRequest.onsuccess", "request.onsuccess")}} handler on the other hand will run if the request returns successfully, meaning the database was successfully opened. If this is the case, an object representing the opened database becomes available in the {{domxref("IDBRequest.result", "request.result")}} property, allowing us to manipulate the database. We store this in the <code>db</code> variable we created earlier for later use. We also run a custom function called <code>displayData()</code>, which displays the data in the database inside the {{HTMLElement("ul")}}. We run it now so that the notes already in the database are displayed as soon as the page loads. You'll see this defined later on.</p> + </li> + <li> + <p>Finally for this section, we'll add probably the most important event handler for setting up the database: {{domxref("IDBOpenDBRequest.onupgradeneeded", "request.onupdateneeded")}}. This handler runs if the database has not already been set up, or if the database is opened with a bigger version number than the existing stored database (when performing an upgrade). Add the following code, below your previous handler:</p> + + <pre class="brush: js notranslate">// Setup the database tables if this has not already been done +request.onupgradeneeded = function(e) { + // Grab a reference to the opened database + let db = e.target.result; + + // Create an objectStore to store our notes in (basically like a single table) + // including a auto-incrementing key + let objectStore = db.createObjectStore('notes_os', { keyPath: 'id', autoIncrement:true }); + + // Define what data items the objectStore will contain + objectStore.createIndex('title', 'title', { unique: false }); + objectStore.createIndex('body', 'body', { unique: false }); + + console.log('Database setup complete'); +};</pre> + + <p>This is where we define the schema (structure) of our database; that is, the set of columns (or fields) it contains. Here we first grab a reference to the existing database from <code>e.target.result</code> (the event target's <code>result</code> property), which is the <code>request</code> object. This is equivalent to the line <code>db = request.result;</code> inside the <code>onsuccess</code> handler, but we need to do this separately here because the <code>onupgradeneeded</code> handler (if needed) will run before the <code>onsuccess</code> handler, meaning that the <code>db</code> value wouldn't be available if we didn't do this.</p> + + <p>We then use {{domxref("IDBDatabase.createObjectStore()")}} to create a new object store inside our opened database called <code>notes_os</code>. This is equivalent to a single table in a conventional database system. We've given it the name notes, and also specified an <code>autoIncrement</code> key field called <code>id</code> — in each new record this will automatically be given an incremented value — the developer doesn't need to set this explicitly. Being the key, the <code>id</code> field will be used to uniquely identify records, such as when deleting or displaying a record.</p> + + <p>We also create two other indexes (fields) using the {{domxref("IDBObjectStore.createIndex()")}} method: <code>title</code> (which will contain a title for each note), and <code>body</code> (which will contain the body text of the note).</p> + </li> +</ol> + +<p>So with this simple database schema set up, when we start adding records to the database; each one will be represented as an object along these lines:</p> + +<pre class="brush: js notranslate"><span class="message-body-wrapper"><span class="message-flex-body"><span class="devtools-monospace message-body"><span class="objectBox objectBox-object"><span class="objectLeftBrace">{ + </span><span class="nodeName">title</span><span class="objectEqual">: </span><span class="objectBox objectBox-string">"Buy milk"</span>, + <span class="nodeName">body</span><span class="objectEqual">: </span><span class="objectBox objectBox-string">"Need both cows milk and soya."</span>, + <span class="nodeName">id</span><span class="objectEqual">: </span><span class="objectBox objectBox-number">8</span></span></span></span></span><span class="message-body-wrapper"><span class="message-flex-body"><span class="devtools-monospace message-body"><span class="objectBox objectBox-object"><span class="objectRightBrace"> +}</span></span></span></span></span></pre> + +<h3 id="Adding_data_to_the_database">Adding data to the database</h3> + +<p>Now let's look at how we can add records to the database. This will be done using the form on our page.</p> + +<p>Below your previous event handler (but still inside the <code>window.onload</code> handler), add the following line, which sets up an <code>onsubmit</code> handler that runs a function called <code>addData()</code> when the form is submitted (when the submit {{htmlelement("button")}} is pressed leading to a successful form submission):</p> + +<pre class="brush: js notranslate">// Create an onsubmit handler so that when the form is submitted the addData() function is run +form.onsubmit = addData;</pre> + +<p>Now let's define the <code>addData()</code> function. Add this below your previous line:</p> + +<pre class="brush: js notranslate">// Define the addData() function +function addData(e) { + // prevent default - we don't want the form to submit in the conventional way + e.preventDefault(); + + // grab the values entered into the form fields and store them in an object ready for being inserted into the DB + let newItem = { title: titleInput.value, body: bodyInput.value }; + + // open a read/write db transaction, ready for adding the data + let transaction = db.transaction(['notes_os'], 'readwrite'); + + // call an object store that's already been added to the database + let objectStore = transaction.objectStore('notes_os'); + + // Make a request to add our newItem object to the object store + var request = objectStore.add(newItem); + request.onsuccess = function() { + // Clear the form, ready for adding the next entry + titleInput.value = ''; + bodyInput.value = ''; + }; + + // Report on the success of the transaction completing, when everything is done + transaction.oncomplete = function() { + console.log('Transaction completed: database modification finished.'); + + // update the display of data to show the newly added item, by running displayData() again. + displayData(); + }; + + transaction.onerror = function() { + console.log('Transaction not opened due to error'); + }; +}</pre> + +<p>This is quite complex; breaking it down, we:</p> + +<ul> + <li>Run {{domxref("Event.preventDefault()")}} on the event object to stop the form actually submitting in the conventional manner (this would cause a page refresh and spoil the experience).</li> + <li>Create an object representing a record to enter into the database, populating it with values from the form inputs. note that we don't have to explicitly include an <code>id</code> value — as we explained earlier, this is auto-populated.</li> + <li>Open a <code>readwrite</code> transaction against the <code>notes_os</code> object store using the {{domxref("IDBDatabase.transaction()")}} method. This transaction object allows us to access the object store so we can do something to it, e.g. add a new record.</li> + <li>Access the object store using the {{domxref("IDBTransaction.objectStore()")}} method, saving the result in the <code>objectStore</code> variable.</li> + <li>Add the new record to the database using {{domxref("IDBObjectStore.add()")}}. This creates a request object, in the same fashion as we've seen before.</li> + <li>Add a bunch of event handlers to the <code>request</code> and the <code>transaction</code> to run code at critical points in the lifecycle. Once the request has succeeded, we clear the form inputs ready for entering the next note. Once the transaction has completed, we run the <code>displayData()</code> function again to update the display of notes on the page.</li> +</ul> + +<h3 id="Displaying_the_data">Displaying the data</h3> + +<p>We've referenced <code>displayData()</code> twice in our code already, so we'd probably better define it. Add this to your code, below the previous function definition:</p> + +<pre class="brush: js notranslate">// Define the displayData() function +function displayData() { + // Here we empty the contents of the list element each time the display is updated + // If you didn't do this, you'd get duplicates listed each time a new note is added + while (list.firstChild) { + list.removeChild(list.firstChild); + } + + // Open our object store and then get a cursor - which iterates through all the + // different data items in the store + let objectStore = db.transaction('notes_os').objectStore('notes_os'); + objectStore.openCursor().onsuccess = function(e) { + // Get a reference to the cursor + let cursor = e.target.result; + + // If there is still another data item to iterate through, keep running this code + if(cursor) { + // Create a list item, h3, and p to put each data item inside when displaying it + // structure the HTML fragment, and append it inside the list + let listItem = document.createElement('li'); + let h3 = document.createElement('h3'); + let para = document.createElement('p'); + + listItem.appendChild(h3); + listItem.appendChild(para); + list.appendChild(listItem); + + // Put the data from the cursor inside the h3 and para + h3.textContent = cursor.value.title; + para.textContent = cursor.value.body; + + // Store the ID of the data item inside an attribute on the listItem, so we know + // which item it corresponds to. This will be useful later when we want to delete items + listItem.setAttribute('data-note-id', cursor.value.id); + + // Create a button and place it inside each listItem + let deleteBtn = document.createElement('button'); + listItem.appendChild(deleteBtn); + deleteBtn.textContent = 'Delete'; + + // Set an event handler so that when the button is clicked, the deleteItem() + // function is run + deleteBtn.onclick = deleteItem; + + // Iterate to the next item in the cursor + cursor.continue(); + } else { + // Again, if list item is empty, display a 'No notes stored' message + if(!list.firstChild) { + let listItem = document.createElement('li'); + listItem.textContent = 'No notes stored.'; + list.appendChild(listItem); + } + // if there are no more cursor items to iterate through, say so + console.log('Notes all displayed'); + } + }; +}</pre> + +<p>Again, let's break this down:</p> + +<ul> + <li>First we empty out the {{htmlelement("ul")}} element's content, before then filling it with the updated content. If you didn't do this, you'd end up with a huge list of duplicated content being added to with each update.</li> + <li>Next, we get a reference to the <code>notes_os</code> object store using {{domxref("IDBDatabase.transaction()")}} and {{domxref("IDBTransaction.objectStore()")}} like we did in <code>addData()</code>, except here we are chaining them together in one line.</li> + <li>The next step is to use {{domxref("IDBObjectStore.openCursor()")}} method to open a request for a cursor — this is a construct that can be used to iterate over the records in an object store. We chain an <code>onsuccess</code> handler on to the end of this line to make the code more concise — when the cursor is successfully returned, the handler is run.</li> + <li>We get a reference to the cursor itself (an {{domxref("IDBCursor")}} object) using let <code>cursor = e.target.result</code>.</li> + <li>Next, we check to see if the cursor contains a record from the datastore (<code>if(cursor){ ... }</code>) — if so, we create a DOM fragment, populate it with the data from the record, and insert it into the page (inside the <code><ul></code> element). We also include a delete button that, when clicked, will delete that note by running the <code>deleteItem()</code> function, which we will look at in the next section.</li> + <li>At the end of the <code>if</code> block, we use the {{domxref("IDBCursor.continue()")}} method to advance the cursor to the next record in the datastore, and run the content of the <code>if</code> block again. If there is another record to iterate to, this causes it to be inserted into the page, and then <code>continue()</code> is run again, and so on.</li> + <li>When there are no more records to iterate over, <code>cursor</code> will return <code>undefined</code>, and therefore the <code>else</code> block will run instead of the <code>if</code> block. This block checks whether any notes were inserted into the <code><ul></code> — if not, it inserts a message to say no note was stored.</li> +</ul> + +<h3 id="Deleting_a_note">Deleting a note</h3> + +<p>As stated above, when a note's delete button is pressed, the note is deleted. This is achieved by the <code>deleteItem()</code> function, which looks like so:</p> + +<pre class="brush: js notranslate">// Define the deleteItem() function +function deleteItem(e) { + // retrieve the name of the task we want to delete. We need + // to convert it to a number before trying it use it with IDB; IDB key + // values are type-sensitive. + let noteId = Number(e.target.parentNode.getAttribute('data-note-id')); + + // open a database transaction and delete the task, finding it using the id we retrieved above + let transaction = db.transaction(['notes_os'], 'readwrite'); + let objectStore = transaction.objectStore('notes_os'); + let request = objectStore.delete(noteId); + + // report that the data item has been deleted + transaction.oncomplete = function() { + // delete the parent of the button + // which is the list item, so it is no longer displayed + e.target.parentNode.parentNode.removeChild(e.target.parentNode); + console.log('Note ' + noteId + ' deleted.'); + + // Again, if list item is empty, display a 'No notes stored' message + if(!list.firstChild) { + let listItem = document.createElement('li'); + listItem.textContent = 'No notes stored.'; + list.appendChild(listItem); + } + }; +}</pre> + +<ul> + <li>The first part of this could use some explaining — we retrieve the ID of the record to be deleted using <code>Number(e.target.parentNode.getAttribute('data-note-id'))</code> — recall that the ID of the record was saved in a <code>data-note-id</code> attribute on the <code><li></code> when it was first displayed. We do however need to pass the attribute through the global built-in <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number">Number()</a></code> object as it is of datatype string, and therefore wouldn't be recognized by the database, which expects a number.</li> + <li>We then get a reference to the object store using the same pattern we've seen previously, and use the {{domxref("IDBObjectStore.delete()")}} method to delete the record from the database, passing it the ID.</li> + <li>When the database transaction is complete, we delete the note's <code><li></code> from the DOM, and again do the check to see if the <code><ul></code> is now empty, inserting a note as appropriate.</li> +</ul> + +<p>So that's it! Your example should now work.</p> + +<p>If you are having trouble with it, feel free to <a href="https://mdn.github.io/learning-area/javascript/apis/client-side-storage/indexeddb/notes/">check it against our live example</a> (see the <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/client-side-storage/indexeddb/notes/index.js">source code</a> also).</p> + +<h3 id="Storing_complex_data_via_IndexedDB">Storing complex data via IndexedDB</h3> + +<p>As we mentioned above, IndexedDB can be used to store more than just simple text strings. You can store just about anything you want, including complex objects such as video or image blobs. And it isn't much more difficult to achieve than any other type of data.</p> + +<p>To demonstrate how to do it, we've written another example called <a href="https://github.com/mdn/learning-area/tree/master/javascript/apis/client-side-storage/indexeddb/video-store">IndexedDB video store</a> (see it <a href="https://mdn.github.io/learning-area/javascript/apis/client-side-storage/indexeddb/video-store/">running live here also</a>). When you first run the example, it downloads all the videos from the network, stores them in an IndexedDB database, and then displays the videos in the UI inside {{htmlelement("video")}} elements. The second time you run it, it finds the videos in the database and gets them from there instead before displaying them — this makes subsequent loads much quicker and less bandwidth-hungry.</p> + +<p>Let's walk through the most interesting parts of the example. We won't look at it all — a lot of it is similar to the previous example, and the code is well-commented.</p> + +<ol> + <li> + <p>For this simple example, we've stored the names of the videos to fetch in an array of objects:</p> + + <pre class="brush: js notranslate">const videos = [ + { 'name' : 'crystal' }, + { 'name' : 'elf' }, + { 'name' : 'frog' }, + { 'name' : 'monster' }, + { 'name' : 'pig' }, + { 'name' : 'rabbit' } +];</pre> + </li> + <li> + <p>To start with, once the database is successfully opened we run an <code>init()</code> function. This loops through the different video names, trying to load a record identified by each name from the <code>videos</code> database.</p> + + <p>If each video is found in the database (easily checked by seeing whether <code>request.result</code> evaluates to <code>true</code> — if the record is not present, it will be <code>undefined</code>), its video files (stored as blobs) and the video name are passed straight to the <code>displayVideo()</code> function to place them in the UI. If not, the video name is passed to the <code>fetchVideoFromNetwork()</code> function to ... you guessed it — fetch the video from the network.</p> + + <pre class="brush: js notranslate">function init() { + // Loop through the video names one by one + for(let i = 0; i < videos.length; i++) { + // Open transaction, get object store, and get() each video by name + let objectStore = db.transaction('videos_os').objectStore('videos_os'); + let request = objectStore.get(videos[i].name); + request.onsuccess = function() { + // If the result exists in the database (is not undefined) + if(request.result) { + // Grab the videos from IDB and display them using displayVideo() + console.log('taking videos from IDB'); + displayVideo(request.result.mp4, request.result.webm, request.result.name); + } else { + // Fetch the videos from the network + fetchVideoFromNetwork(videos[i]); + } + }; + } +}</pre> + </li> + <li> + <p>The following snippet is taken from inside <code>fetchVideoFromNetwork()</code> — here we fetch MP4 and WebM versions of the video using two separate {{domxref("fetch()", "WindowOrWorkerGlobalScope.fetch()")}} requests. We then use the {{domxref("blob()", "Body.blob()")}} method to extract each response's body as a blob, giving us an object representation of the videos that can be stored and displayed later on.</p> + + <p>We have a problem here though — these two requests are both asynchronous, but we only want to try to display or store the video when both promises have fulfilled. Fortunately there is a built-in method that handles such a problem — {{jsxref("Promise.all()")}}. This takes one argument — references to all the individual promises you want to check for fulfillment placed in an array — and is itself promise-based.</p> + + <p>When all those promises have fulfilled, the <code>all()</code> promise fulfills with an array containing all the individual fulfillment values. Inside the <code>all()</code> block, you can see that we then call the <code>displayVideo()</code> function like we did before to display the videos in the UI, then we also call the <code>storeVideo()</code> function to store those videos inside the database.</p> + + <pre class="brush: js notranslate">let mp4Blob = fetch('videos/' + video.name + '.mp4').then(response => + response.blob() +); +let webmBlob = fetch('videos/' + video.name + '.webm').then(response => + response.blob() +); + +// Only run the next code when both promises have fulfilled +Promise.all([mp4Blob, webmBlob]).then(function(values) { + // display the video fetched from the network with displayVideo() + displayVideo(values[0], values[1], video.name); + // store it in the IDB using storeVideo() + storeVideo(values[0], values[1], video.name); +});</pre> + </li> + <li> + <p>Let's look at <code>storeVideo()</code> first. This is very similar to the pattern you saw in the previous example for adding data to the database — we open a <code>readwrite</code> transaction and get a reference to our <code>videos_os</code> object store, create an object representing the record to add to the database, then simply add it using {{domxref("IDBObjectStore.add()")}}.</p> + + <pre class="brush: js notranslate">function storeVideo(mp4Blob, webmBlob, name) { + // Open transaction, get object store; make it a readwrite so we can write to the IDB + let objectStore = db.transaction(['videos_os'], 'readwrite').objectStore('videos_os'); + // Create a record to add to the IDB + let record = { + mp4 : mp4Blob, + webm : webmBlob, + name : name + } + + // Add the record to the IDB using add() + let request = objectStore.add(record); + + ... + +};</pre> + </li> + <li> + <p>Last but not least, we have <code>displayVideo()</code>, which creates the DOM elements needed to insert the video in the UI and then appends them to the page. The most interesting parts of this are those shown below — to actually display our video blobs in a <code><video></code> element, we need to create object URLs (internal URLs that point to the video blobs stored in memory) using the {{domxref("URL.createObjectURL()")}} method. Once that is done, we can set the object URLs to be the values of our {{htmlelement("source")}} element's <code>src</code> attributes, and it works fine.</p> + + <pre class="brush: js notranslate">function displayVideo(mp4Blob, webmBlob, title) { + // Create object URLs out of the blobs + let mp4URL = URL.createObjectURL(mp4Blob); + let webmURL = URL.createObjectURL(webmBlob); + + ... + + let video = document.createElement('video'); + video.controls = true; + let source1 = document.createElement('source'); + source1.src = mp4URL; + source1.type = 'video/mp4'; + let source2 = document.createElement('source'); + source2.src = webmURL; + source2.type = 'video/webm'; + + ... +}</pre> + </li> +</ol> + +<h2 id="Offline_asset_storage">Offline asset storage</h2> + +<p>The above example already shows how to create an app that will store large assets in an IndexedDB database, avoiding the need to download them more than once. This is already a great improvement to the user experience, but there is still one thing missing — the main HTML, CSS, and JavaScript files still need to downloaded each time the site is accessed, meaning that it won't work when there is no network connection.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/15759/ff-offline.png" style="border-style: solid; border-width: 1px; display: block; height: 307px; margin: 0px auto; width: 765px;"></p> + +<p>This is where <a href="/en-US/docs/Web/API/Service_Worker_API">Service workers</a> and the closely-related <a href="/en-US/docs/Web/API/Cache">Cache API</a> come in.</p> + +<p>A service worker is a JavaScript file that, simply put, is registered against a particular origin (web site, or part of a web site at a certain domain) when it is accessed by a browser. When registered, it can control pages available at that origin. It does this by sitting between a loaded page and the network and intercepting network requests aimed at that origin.</p> + +<p>When it intercepts a request, it can do anything you wish to it (see <a href="/en-US/docs/Web/API/Service_Worker_API#Other_use_case_ideas">use case ideas</a>), but the classic example is saving the network responses offline and then providing those in response to a request instead of the responses from the network. In effect, it allows you to make a web site work completely offline.</p> + +<p>The Cache API is a another client-side storage mechanism, with a bit of a difference — it is designed to save HTTP responses, and so works very well with service workers.</p> + +<div class="note"> +<p><strong>Note</strong>: Service workers and Cache are supported in most modern browsers now. At the time of writing, Safari was still busy implementing it, but it should be there soon.</p> +</div> + +<h3 id="A_service_worker_example">A service worker example</h3> + +<p>Let's look at an example, to give you a bit of an idea of what this might look like. We have created another version of the video store example we saw in the previous section — this functions identically, except that it also saves the HTML, CSS, and JavaScript in the Cache API via a service worker, allowing the example to run offline!</p> + +<p>See <a href="https://mdn.github.io/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/">IndexedDB video store with service worker running live</a>, and also <a href="https://github.com/mdn/learning-area/tree/master/javascript/apis/client-side-storage/cache-sw/video-store-offline">see the source code</a>.</p> + +<h4 id="Registering_the_service_worker">Registering the service worker</h4> + +<p>The first thing to note is that there's an extra bit of code placed in the main JavaScript file (see <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/client-side-storage/cache-sw/video-store-offline/index.js">index.js</a>). First we do a feature detection test to see if the <code>serviceWorker</code> member is available in the {{domxref("Navigator")}} object. If this returns true, then we know that at least the basics of service workers are supported. Inside here we use the {{domxref("ServiceWorkerContainer.register()")}} method to register a service worker contained in the <code>sw.js</code> file against the origin it resides at, so it can control pages in the same directory as it, or subdirectories. When its promise fulfills, the service worker is deemed registered.</p> + +<pre class="brush: js notranslate"> // Register service worker to control making site work offline + + if('serviceWorker' in navigator) { + navigator.serviceWorker + .register('/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/sw.js') + .then(function() { console.log('Service Worker Registered'); }); + }</pre> + +<div class="note"> +<p><strong>Note</strong>: The given path to the <code>sw.js</code> file is relative to the site origin, not the JavaScript file that contains the code. The service worker is at <code>https://mdn.github.io/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/sw.js</code>. The origin is <code>https://mdn.github.io</code>, and therefore the given path has to be <code>/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/sw.js</code>. If you wanted to host this example on your own server, you'd have to change this accordingly. This is rather confusing, but it has to work this way for security reasons.</p> +</div> + +<h4 id="Installing_the_service_worker">Installing the service worker</h4> + +<p>The next time any page under the service worker's control is accessed (e.g. when the example is reloaded), the service worker is installed against that page, meaning that it will start controlling it. When this occurs, an <code>install</code> event is fired against the service worker; you can write code inside the service worker itself that will respond to the installation.</p> + +<p>Let's look at an example, in the <a href="https://github.com/mdn/learning-area/blob/master/javascript/apis/client-side-storage/cache-sw/video-store-offline/sw.js">sw.js</a> file (the service worker). You'll see that the install listener is registered against <code>self</code>. This <code>self</code> keyword is a way to refer to the global scope of the service worker from inside the service worker file.</p> + +<p>Inside the <code>install</code> handler we use the {{domxref("ExtendableEvent.waitUntil()")}} method, available on the event object, to signal that the browser shouldn't complete installation of the service worker until after the promise inside it has fulfilled successfully.</p> + +<p>Here is where we see the Cache API in action. We use the {{domxref("CacheStorage.open()")}} method to open a new cache object in which responses can be stored (similar to an IndexedDB object store). This promise fulfills with a {{domxref("Cache")}} object representing the <code>video-store</code> cache. We then use the {{domxref("Cache.addAll()")}} method to fetch a series of assets and add their responses to the cache.</p> + +<pre class="brush: js notranslate">self.addEventListener('install', function(e) { + e.waitUntil( + caches.open('video-store').then(function(cache) { + return cache.addAll([ + '/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/', + '/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/index.html', + '/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/index.js', + '/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/style.css' + ]); + }) + ); +});</pre> + +<p>That's it for now, installation done.</p> + +<h4 id="Responding_to_further_requests">Responding to further requests</h4> + +<p>With the service worker registered and installed against our HTML page, and the relevant assets all added to our cache, we are nearly ready to go. There is only one more thing to do, write some code to respond to further network requests.</p> + +<p>This is what the second bit of code in <code>sw.js</code> does. We add another listener to the service worker global scope, which runs the handler function when the <code>fetch</code> event is raised. This happens whenever the browser makes a request for an asset in the directory the service worker is registered against.</p> + +<p>Inside the handler we first log the URL of the requested asset. We then provide a custom response to the request, using the {{domxref("FetchEvent.respondWith()")}} method.</p> + +<p>Inside this block we use {{domxref("CacheStorage.match()")}} to check whether a matching request (i.e. matches the URL) can be found in any cache. This promise fulfills with the matching response if a match is not found, or <code>undefined</code> if it isn't.</p> + +<p>If a match is found, we simply return it as the custom response. If not, we <a href="/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch">fetch()</a> the response from the network and return that instead.</p> + +<pre class="brush: js notranslate">self.addEventListener('fetch', function(e) { + console.log(e.request.url); + e.respondWith( + caches.match(e.request).then(function(response) { + return response || fetch(e.request); + }) + ); +});</pre> + +<p>And that is it for our simple service worker. There is a whole load more you can do with them — for a lot more detail, see the <a href="https://serviceworke.rs/">service worker cookbook</a>. And thanks to Paul Kinlan for his article <a href="https://developers.google.com/web/fundamentals/codelabs/offline/">Adding a Service Worker and Offline into your Web App</a>, which inspired this simple example.</p> + +<h4 id="Testing_the_example_offline">Testing the example offline</h4> + +<p>To test our <a href="https://mdn.github.io/learning-area/javascript/apis/client-side-storage/cache-sw/video-store-offline/">service worker example</a>, you'll need to load it a couple of times to make sure it is installed. Once this is done, you can:</p> + +<ul> + <li>Try unplugging your network/turning your Wifi off.</li> + <li>Select <em>File > Work Offline</em> if you are using Firefox.</li> + <li>Go to the devtools, then choose <em>Application > Service Workers</em>, then check the <em>Offline</em> checkbox if you are using Chrome.</li> +</ul> + +<p>If you refresh your example page again, you should still see it load just fine. Everything is stored offline — the page assets in a cache, and the videos in an IndexedDB database.</p> + +<h2 id="Summary">Summary</h2> + +<p>That's it for now. We hope you've found our rundown of client-side storage technologies useful.</p> + +<h2 id="See_also">See also</h2> + +<ul> + <li><a href="/en-US/docs/Web/API/Web_Storage_API">Web storage API</a></li> + <li><a href="/en-US/docs/Web/API/IndexedDB_API">IndexedDB API</a></li> + <li><a href="/en-US/docs/Web/HTTP/Cookies">Cookies</a></li> + <li><a href="/en-US/docs/Web/API/Service_Worker_API">Service worker API</a></li> +</ul> + +<p>{{PreviousMenu("Learn/JavaScript/Client-side_web_APIs/Video_and_audio_APIs", "Learn/JavaScript/Client-side_web_APIs")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Introduction">Introduction to web APIs</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Manipulating_documents">Manipulating documents</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Fetching_data">Fetching data from the server</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Third_party_APIs">Third party APIs</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Drawing_graphics">Drawing graphics</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Video_and_audio_APIs">Video and audio APIs</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Client-side_storage">Client-side storage</a></li> +</ul> diff --git a/files/ko/learn/javascript/client-side_web_apis/index.html b/files/ko/learn/javascript/client-side_web_apis/index.html new file mode 100644 index 0000000000..a02e2bc0c4 --- /dev/null +++ b/files/ko/learn/javascript/client-side_web_apis/index.html @@ -0,0 +1,37 @@ +--- +title: Client-side web APIs +slug: Learn/JavaScript/Client-side_web_APIs +translation_of: Learn/JavaScript/Client-side_web_APIs +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">웹 사이트 또는 응용 프로그램 용 client-side JavaScript를 작성할때 API (응용 프로그램 프로그래밍 인터페이스)를 사용하지 않으면 많은것을 만들기 어렵습니다. API는 사이트가 실행되고 있는 브라우저와 운영 체제의 다양한 부분 그리고 웹 사이트 혹은 서비스의 데이터를 다룰 수 있는 인터페이스입니다. 이번장에서 우리는 API가 무엇인지, 그리고 개발할 때 자주 접하게 될 보편적인 API를 사용하는 방법에 대해 살펴볼 것입니다.</p> + +<h2 id="선행사항">선행사항</h2> + +<p>다음의 문서를 미리 보고 오시는것을 권장합니다. (<a href="/ko/docs/Learn/JavaScript/First_steps">First steps</a>, <a href="/ko/docs/Learn/JavaScript/Building_blocks">Building blocks</a>, and <a href="/ko/docs/Learn/JavaScript/Objects">JavaScript objects</a>). 이 모듈은 클라이언트 측 JavaScript 예제를 사용하지 않고 유용하게 사용할 수 있기 때문에 간단한 API 사용법을 상당히 많이 사용합니다. 여기에서는 핵심 자바 스크립트 언어에 대한 지식이 있다고 가정하고 일반적인 웹 API를 좀 더 자세하게 살펴보면서 한 단계 올라갑니다. 이번장에서는 심플한 API사용방법을 여럿 보도록 하겠습니다. 이 API들은 client-side 자바스크립트를 만드는데 도움이 많이 될 것입니다.</p> + +<p><a href="/en-US/docs/Learn/HTML">HTM</a>과<a href="/en-US/docs/Learn/CSS">CSS</a>에 관한 기본지식이 있으면 좋습니다!</p> + +<div class="note"> +<p><strong>Note</strong>: 코드를 작성 할 수 없는 디바이스에서 작업하는 경우 <a href="http://jsbin.com/">JSBin</a> 또는 <a href="https://thimble.mozilla.org/">Thimble</a>.과 같은 온라인 코딩 프로그램에서 코드 예제를 시험해 볼 수 있습니다.</p> +</div> + +<h2 id="Guides">Guides</h2> + +<dl> + <dt><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Introduction">Introduction to web APIs</a></dt> + <dd>우선, 높은 수준의 API를 먼저 살펴볼 것입니다. API는 무엇이며, 어떻게 작동하며, 코드에서 어떻게 사용하고 구조화되어 있는지 확인합니다. 또한 API의 다른 주요 클래스가 무엇인지, 그리고 용도가 무엇인지 살펴볼 것입니다.</dd> + <dt><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Manipulating_documents">Manipulating documents</a></dt> + <dd>웹 페이지와 앱을 작성할 때 많이 하는 것중 하나는 웹 문서를 다루는 것입니다. 보통 {{domxref ( "Document")}} 객체를 많이 사용하는 HTML 및 스타일 정보를 제어하기위한 API 집합 인 DOM (Document Object Model)을 사용합니다. 여기서는 흥미로운 방식으로 환경을 변경할 수 있는 API와 함께 DOM을 사용하는 방법에 대해 자세히 설명합니다.</dd> + <dt><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Fetching_data">Fetching data from the server</a></dt> + <dd>최신 웹 사이트 및 응용 프로그램에서 필요한 작업중 하나는 완전히 새로운 페이지를 로드 할 필요없이 서버에서 개별 데이터를 가져와 웹 페이지의 일부분만 업데이트하는 것입니다. 이렇게 하면 사이트의 성능과 동작에 큰 영향을 줍니다. 여기서는 이 개념을 설명하고 {{domxref ( "XMLHttpRequest")}}나 <a href="https://developer.mozilla.org/ko/docs/Web/API/Fetch_API">Fetch API</a>와 같은 기술을 살펴 보겠습니다</dd> + <dt><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Third_party_APIs">Third party APIs</a></dt> + <dd>지금까지 살펴본 API는 브라우저에 내장되어 있지만 모든 API가 지원되지는 않습니다. 예를들면 Google Maps, Twitter, Facebook, PayPal 등과 같은 많은 대형 웹 사이트와 서비스가 있고 여기에는 개발자 자신의 데이터 (예 : 블로그에 트위터 스트림 표시) 또는 서비스 (예 : 사이트에 맞춤 Google지도 표시, Facebook 로그인을 사용하여 사용자 로그인)가 있습니다.여기서는 브라우저 API와 타사 API의 차이점을 살펴본 후 일반적인 API 사용법을 보겠습니다.</dd> + <dt><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Drawing_graphics">Drawing graphics</a></dt> + <dd>브라우저에는 <a href="https://developer.mozilla.org/en-US/docs/Web/SVG">SVG</a> (Scalable Vector Graphics) 언어부터 HTML {{htmlelement ( "canvas")}} 요소 (<a href="https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API">The Canvas API</a> 및 <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API">WebGL</a> 참조)를 그리는 데 필요한 API에 이르기까지 매우 강력한 그래픽 프로그래밍 도구가 포함되어 있습니다. 여기서는 Canvas API에 대한 소개와 더 많은 정보를 얻을 수있는 추가 자료를 제공합니다.</dd> + <dt><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Video_and_audio_APIs">Video and audio APIs</a></dt> + <dd>HTML5에는 문서 ({{htmlelement ( "video")}} 및 {{htmlelement ( "audio")}}에 미디어를 포함하기위한 요소가 포함되어 있으며 재생, 탐색 등을 제어하는 자체 API가 제공됩니다. 이문서에서는 사용자 커스텀 재생 컨트롤 만들기와 같은 일반적인 작업을 수행하는 방법을 보여줍니다.</dd> + <dt><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Client-side_storage">Client-side storage</a></dt> + <dd>최신 웹 브라우저에는 웹 사이트와 관련된 데이터를 저장하고 필요할 때 검색하여 장기간 데이터를 유지하고 오프라인으로 사이트를 저장하는 등 다양한 기술을 사용할 수 있습니다. 이 기사에서는 이러한 작업 방식에 대한 기본적인 내용을 설명합니다.</dd> +</dl> diff --git a/files/ko/learn/javascript/first_steps/a_first_splash/index.html b/files/ko/learn/javascript/first_steps/a_first_splash/index.html new file mode 100644 index 0000000000..fd29057f86 --- /dev/null +++ b/files/ko/learn/javascript/first_steps/a_first_splash/index.html @@ -0,0 +1,680 @@ +--- +title: 자바스크립트 기초 +slug: Learn/JavaScript/First_steps/A_first_splash +translation_of: Learn/JavaScript/First_steps/A_first_splash +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/First_steps/What_is_JavaScript", "Learn/JavaScript/First_steps/What_went_wrong", "Learn/JavaScript/First_steps")}}</div> + +<p class="summary">이제 우리는 자바스크립트에 대한 이론적인 몇몇 부분을 살펴볼 것이다. 이곳에서 무엇을 할 수 있는지 실용적인 연습을 통한 자바스크립의 기본적 사항들을 다루는 과정이 되겠다. 하나하나씩 "숫자맞추기" 게임을 간단하게 구성해나갈 것이다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">알아야할 것들:</th> + <td>기본적인 컴퓨터 사용과 HTML CSS와 자바스크립트에 대해 알아야 함.</td> + </tr> + <tr> + <th scope="row">수업 목표:</th> + <td>자바스크립트로 코딩하는 것을 처음으로 알아보고 자바스크립트로 쓰여진 프로그램이 가지고 있는 특징들을 조금이라도 이해한다.</td> + </tr> + </tbody> +</table> + +<p>지금현재로서는 코드를 자세히 이해하려고 하지는 않을 것이다. 단지 지금은 넓게 개념을 이해하고, (다른 프로그래밍 언어를 포함해) 자바스크립트가 어떻게 운용되는지에 대한 아이디어가 필요하다. 자, 이제부터 자세한 부분에 대해 공부하고 알아보자!</p> + +<div class="note"> +<p>Note: 자바스크립트에서 보는 다양한 요소들은 여타 프로그래밍 언어와 거의 똑같다.(함수나 반복문 등) 언어마다 문법이 다를 뿐이지 개념은 넓은범위에서 보자면 일맥상통하다.</p> +</div> + +<h2 id="프로그래머처럼_사고하기">프로그래머처럼 사고하기</h2> + +<p>프로그래밍에서 가장 어려운 것은 우리가 배우려고 하는 문법이 아닌, 어떻게 실생활의 문제를 프로그래밍으로 적용시킬까하는 문제이다. 이제부터는 프로그래머처럼 생각하는 것이 필요하다. 이는 일반적으로 프로그램이 필요한 부분과 어떻게 코드가 문제를 해결하기위해 작동되고, 협업해야 되는지에 대한 설명을 알고있어야 된다는 것이다.</p> + +<p>이는 프로그래밍 문법에 대한 경험과 노력, 그리고 창의성을 비롯한 노력의 조합이 필요하다. 코드를 많이 작성할수록 얻는 것은 더 많아질 것이다. 지금 당장 "프로그래머의 사고능력"으로 발전시킨다고는 보장하지는 못하지만, 이 수업을 통해 여러분들에게 프로그래머처럼 생각하는 많은 연습의 기회는 줄 수 있다.</p> + +<p>이러한 개념을 마음속에 품고, 앞으로 우리가 만들어나갈 예제를 한번 살펴보자. 여기서 실생활의 문제를 프로그래밍할 수 있도록 쪼개는 일반적인 과정을 볼 것이다.</p> + +<h2 id="예제-숫자맞추기">예제-숫자맞추기</h2> + +<p>아래 보이는 간단한 게임을 통해, 프로그램을 구성하는 방법을 알아볼 것이다.</p> + +<div class="hidden"> +<h6 id="Top_hidden_code">Top hidden code</h6> + + + +<pre class="brush: html"><!DOCTYPE html> +<html> + +<head> + <meta charset="utf-8"> + <title>Number guessing game</title> + <style> + html { + font-family: sans-serif; + } + + body { + width: 50%; + max-width: 800px; + min-width: 480px; + margin: 0 auto; + } + + .lastResult { + color: white; + padding: 3px; + } + </style> +</head> + +<body> + <h1>Number guessing game</h1> + <p>We have selected a random number between 1 and 100. See if you can guess it in 10 turns or less. We'll tell you if your guess was too high or too low.</p> + <div class="form"> <label for="guessField">Enter a guess: </label><input type="text" id="guessField" class="guessField"> <input type="submit" value="Submit guess" class="guessSubmit"> </div> + <div class="resultParas"> + <p class="guesses"></p> + <p class="lastResult"></p> + <p class="lowOrHi"></p> + </div> +</body> +<script> + // Your JavaScript goes here + var randomNumber = Math.floor(Math.random() * 100) + 1; + var guesses = document.querySelector('.guesses'); + var lastResult = document.querySelector('.lastResult'); + var lowOrHi = document.querySelector('.lowOrHi'); + var guessSubmit = document.querySelector('.guessSubmit'); + var guessField = document.querySelector('.guessField'); + var guessCount = 1; + var resetButton; + + function checkGuess() { + var userGuess = Number(guessField.value); + if (guessCount === 1) { + guesses.textContent = 'Previous guesses: '; + } + + guesses.textContent += userGuess + ' '; + + if (userGuess === randomNumber) { + lastResult.textContent = 'Congratulations! You got it right!'; + lastResult.style.backgroundColor = 'green'; + lowOrHi.textContent = ''; + setGameOver(); + } else if (guessCount === 10) { + lastResult.textContent = '!!!GAME OVER!!!'; + lowOrHi.textContent = ''; + setGameOver(); + } else { + lastResult.textContent = 'Wrong!'; + lastResult.style.backgroundColor = 'red'; + if(userGuess < randomNumber) { + lowOrHi.textContent='Last guess was too low!' ; + } else if(userGuess > randomNumber) { + lowOrHi.textContent = 'Last guess was too high!'; + } + } + + guessCount++; + guessField.value = ''; + } + + guessSubmit.addEventListener('click', checkGuess); + + function setGameOver() { + guessField.disabled = true; + guessSubmit.disabled = true; + resetButton = document.createElement('button'); + resetButton.textContent = 'Start new game'; + document.body.appendChild(resetButton); + resetButton.addEventListener('click', resetGame); + } + + function resetGame() { + guessCount = 1; + var resetParas = document.querySelectorAll('.resultParas p'); + for(var i = 0 ; i < resetParas.length ; i++) { + resetParas[i].textContent=''; + } + + resetButton.parentNode.removeChild(resetButton); + guessField.disabled = false; + guessSubmit.disabled = false; + guessField.value=''; + guessField.focus(); + lastResult.style.backgroundColor='white'; + randomNumber=Math.floor(Math.random() * 100) + 1; + } +</script> + +</html></pre> + + +</div> + +<p>{{ EmbedLiveSample('Top_hidden_code', '100%', 320) }}</p> + +<p>한 번 실행해서 어떻게 이루어져 있는지 살펴보고 알아보자.</p> + +<p>만약 너의 상사가 예제에 관련되어 다음의 짦은 안내만 주어졌다고 생각해보자.</p> + +<blockquote> +<p>나는 간단하게 숫자 맞추기 게임을 만들고 싶다.1과 100사의 수 중에서 무작위로 선택되어야하고, 플레이어는 10번의 기회안에 그 숫자를 맞춰야 한다. 각 순서마다 숫자를 맞춰는지 틀렸는지는 당연히 알려줘야 하고, 틀렸다면 큰지 작은지도 포함해서 말해야 한다.또한 이전에 써냈던 번호들도 보여줘야 한다. 게임은 플레이어가 숫자를 맞추던가, 기회를 모두 소진하면 끝나게 된다. 게임이 끝나면 플레이어가 다시 게임을 할 것인지 묻게된다.</p> +</blockquote> + +<p>위의 안내문을 보고, 우선 문제를 가능한 한 작게 쪼개서 간단한 작업으로 만드는 것부터 시작하자.</p> + +<ol> + <li>1과 100사이의 숫자 중 무작위로 추출한다.</li> + <li>1부터 플레이어의 차례를 기록한다.</li> + <li>플레이어에게 숫자를 맞출 수 있게 한다.</li> + <li>숫자를 맞추면 어딘가에 저장하고, 사용자는 이전의 추측한 숫자를 볼 수 있도록 한다.</li> + <li>그다음, 숫자가 일치한지 확인한다.</li> + <li>만약 일치한다면: + <ol> + <li>축하 메시지를 표시한다.</li> + <li>더 이상 숫자를 맞출필요가 없다.</li> + <li>플레이어가 다시 게임을 할지 묻는다.</li> + </ol> + </li> + <li>숫자가 틀렸고, 차례가 남아있다면: + <ol> + <li>틀렸다고 알린다.</li> + <li>다른 숫자를 입력할 수 있도록 한다.</li> + <li>차례가 1 증가한다.</li> + </ol> + </li> + <li>숫자가 틀렸고, 차례가 없다면: + <ol> + <li>게임이 종료되었음을 알린다.</li> + <li>더 이상 숫자를 맞출필요가 없다..</li> + <li>플레이어가 다시 게임을 할지 묻는다.</li> + </ol> + </li> + <li>게임이 재시작 되면, 게임의 구조와 UI는 완전히 리셋되며, step1 부터 다시 로직이 시작된다.</li> +</ol> + +<p>이제 다음 단계로 넘어가서 각 단계들을 코드로 어떻게 만들고, 예제 소스와 통합하며, 그와 관련된 자바 스크립트 기능은 무엇인지 살펴보도록 하겠다.</p> + +<h3 id="초기_구성">초기 구성</h3> + +<p>수업에 앞서, 로컬에 <a href="https://github.com/mdn/learning-area/blob/master/javascript/introduction-to-js-1/first-splash/number-guessing-game-start.html">number-guessing-game-start.html</a> 파일을 저장하길 바란다. (<a href="http://mdn.github.io/learning-area/javascript/introduction-to-js-1/first-splash/number-guessing-game-start.html">see it live here</a>). 그러고 파일을 에디터와 브라우저에서 동시에 열어보자. 간단하게 요약된 설명과 추측하는 폼을 볼 때, 아직 숫자를 입력하는 폼은 아무런 기능을 하지 않는다</p> + +<p>여러분들의 코드를 추가하는 부분은 HTML안의 {{htmlelement("script")}} 요소 사이에 있다. </p> + +<pre class="brush: html"><script> + + // Your JavaScript goes here + +</script> +</pre> + +<h3 id="데이터_저장을_위한_변수_추가">데이터 저장을 위한 변수 추가</h3> + +<p>이제 시작해보자! 먼저 {{htmlelement("script")}} 태그안에 다음의 코드들을 추가하자.</p> + +<pre class="brush: js">var randomNumber = Math.floor(Math.random() * 100) + 1; + +var guesses = document.querySelector('.guesses'); +var lastResult = document.querySelector('.lastResult'); +var lowOrHi = document.querySelector('.lowOrHi'); + +var guessSubmit = document.querySelector('.guessSubmit'); +var guessField = document.querySelector('.guessField'); + +var guessCount = 1; +var resetButton;</pre> + +<p>이 코드의 부분은 프로그램에서 사용될 데이터를 저장할 변수를 세팅해준다. 변수들은 기본적으로 값들을 저장하고 있다. (숫자나 문자열 등). 변수들은 var이라는 키워드를 변수의 이름앞에 붙여줌으로써 선언이된다. 변수 에 넣고자 하는 값 앞에 등호(=)를 통해 변수에 값을 지정할 수 있다.</p> + +<p>예제에서</p> + +<ul> + <li>첫번째 변수 <code>randomNumber</code>는 수학적 알고리즘을 통해 계산해 1과 100사이의 임의의 수를 지정한다 .</li> + <li>다음의 세 개의 변수들은 각각 HTML에서 결과 문장을 저장하는 기준으로 저장되고, 코드상에서 나중에 문장에 추가되도록 사용된다. + <pre class="brush: html"><p class="guesses"></p> +<p class="lastResult"></p> +<p class="lowOrHi"></p></pre> + </li> + <li>다음의 2개 변수는 다음의 입력과 버튼을 받고, 추측된 값을 나중에 받도록 하는 역할을 한다. + <pre class="brush: html"><label for="guessField">Enter a guess: </label><input type="text" id="guessField" class="guessField"> +<input type="submit" value="Submit guess" class="guessSubmit"></pre> + </li> + <li>마지막 2개의 변수에는 (얼마나 많은 추측을 했는지) 추측 개수와, 아직은 있지않은 버튼을 리셋하는 변수가 있다.</li> +</ul> + +<div class="note"> +<p><strong>주의</strong>: 앞으로 변수에 대해서는 더 많이 배울 것이다. <a href="https://developer.mozilla.org/en-US/docs/user:chrisdavidmills/variables">next article</a>를 참고해보자.</p> +</div> + +<h3 id="함수">함수</h3> + +<p>다음으로, 아래의 자바스크립트 코드를 추가하자.</p> + +<pre class="brush: js">function checkGuess() { + alert('I am a placeholder'); +}</pre> + +<p>함수는 재사용이 가능한 코드의 묶음으로 한 번만 명시하면 몇번이고 실행이 가능하여 전체적인 코드에서 반복을 줄일 수 있다 . 이는 매우 유용하다. 함수를 정의하는 방법에는 여러가지가 있지만, 일단 여기서는 가장 간단한 방법을 집중적으로 살펴볼 것이다. 앞에 <code>function</code>키워드를 사용하고, 함수의 이름을 작성하며, 함수의 이름 뒤에 괄호를 넣어줌으로서 함수를 정의할 수 있다.그러고 나서 중괄호로 묶어준다. 중괄호 안에는 함수가 호출되면 실행되는 반복적인 코드들이 들어있다.</p> + +<p>코드는 괄호 앞에 위치한 함수의 이름을 적음으로 실행된다.</p> + +<p>코드를 저장하고 브라우저에서 새로고침을 통해 실행해보자.</p> + +<p><a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">developer tools JavaScript console</a>에 들어가서 다음의 문장을 입력해보자</p> + +<pre class="brush: js">checkGuess();</pre> + +<p>"I am a placeholder"라고 알리는 alert를 볼 수 있을 것이다. 여기서는 함수가 호출되면 alert가 생성되는 함수로 정의되어 있다.</p> + +<div class="note"> +<p><strong>Note</strong>:더 많은 함수에 대한 내용은 차후의 학습에서 볼 수 있을 것이다.</p> +</div> + +<h3 id="연산자">연산자</h3> + +<p>자바스크립트의 연산자는 테스트를 진행하고, 수학적인 것을 다루고, 문자열을 결합하는 등의 것들을 가능케한다.</p> + +<p>다음의 코드를 저장하고 브라우저의 페이지에서 보이도록 새로고침 해보자. <a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">개발자 도구 JavaScript 콘솔</a>을 열고 아래 표시된 에제를 입력 해보자. 표시된대로 정확히 입력하고 Return/Enter 키를 누른 후 어떤 결과가 반환되는지 보자. 브라우저 개발자 도구에 쉽게 액세스 할 수 없는 경우, 아래 표시된 간단한 콘솔을 사용 할 수 있다:</p> + +<div class="hidden"> +<h6 id="Hidden_code">Hidden code</h6> + +<pre class="brush: html"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>JavaScript console</title> + <style> + * { + box-sizing: border-box; + } + + html { + background-color: #0C323D; + color: #809089; + font-family: monospace; + } + + body { + max-width: 700px; + } + + p { + margin: 0; + width: 1%; + padding: 0 1%; + font-size: 16px; + line-height: 1.5; + float: left; + } + + .input p { + margin-right: 1%; + } + + .output p { + width: 100%; + } + + .input input { + width: 96%; + float: left; + border: none; + font-size: 16px; + line-height: 1.5; + font-family: monospace; + padding: 0; + background: #0C323D; + color: #809089; + } + + div { + clear: both; + } + + </style> + </head> + <body> + + + </body> + + <script> + var geval = eval; + + function createInput() { + var inputDiv = document.createElement('div'); + var inputPara = document.createElement('p'); + var inputForm = document.createElement('input'); + + inputDiv.setAttribute('class','input'); + inputPara.textContent = '>'; + inputDiv.appendChild(inputPara); + inputDiv.appendChild(inputForm); + document.body.appendChild(inputDiv); + inputDiv.focus(); + + inputForm.addEventListener('change', executeCode); + } + + function executeCode(e) { + try { + var result = geval(e.target.value); + } catch(e) { + var result = 'error — ' + e.message; + } + + var outputDiv = document.createElement('div'); + var outputPara = document.createElement('p'); + + outputDiv.setAttribute('class','output'); + outputPara.textContent = 'Result: ' + result; + outputDiv.appendChild(outputPara); + document.body.appendChild(outputDiv); + + e.target.disabled = true; + e.target.parentNode.style.opacity = '0.5'; + + createInput() + } + + createInput(); + + </script> +</html></pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_code', '100%', 300) }}</p> + +<p>먼저 산술 연산자를 살펴보자.</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">연산자</th> + <th scope="col">이름</th> + <th scope="col">예</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>+</code></td> + <td>더하기 </td> + <td><code>6 + 9</code></td> + </tr> + <tr> + <td><code>-</code></td> + <td>빼기</td> + <td><code>20 - 15</code></td> + </tr> + <tr> + <td><code>*</code></td> + <td>곱하기</td> + <td><code>3 * 7</code></td> + </tr> + <tr> + <td><code>/</code></td> + <td>나누기</td> + <td><code>10 / 5</code></td> + </tr> + </tbody> +</table> + +<p>또한 + 연산자는 문자열들을 서로 연결할때에도 사용된다.(이를 프로그래밍에서 '문자열접합'이라고 한다.) 다음 코드를 입력해보자.</p> + +<pre class="brush: js">var name = 'Bingo'; +name; +var hello = ' says hello!'; +hello; +var greeting = name + hello; +greeting;</pre> + +<p>그리고 '복합 대입 연산자' 라고 불리는 소스를 간단하게 하는 연산자도 있다. 예를 들어, 단순히 새로운 문자열을 기존에 있는 문자열에 추가하고, 그 결과를 반환받는 일을 하고 있다면 다음 코드를 사용할 수 있다.</p> + +<pre class="brush: js">name += ' says hello!';</pre> + +<p>이 코드는 다음 코드와 같은 의미이다.</p> + +<pre class="brush: js">name = name + ' says hello!';</pre> + +<p>참/거짓을 판명할때 (조건문이 있을 때 — {{anch("Conditionals", "아래")}}를 참조하자) , 비교연산자를 사용한다.</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Operator</th> + <th scope="col">Name</th> + <th scope="col">Example</th> + </tr> + <tr> + <td><code>===</code></td> + <td>Strict equality (is it exactly the same?)</td> + <td><code>5 === 2 + 4</code></td> + </tr> + <tr> + <td><code>!==</code></td> + <td>Non-equality (is it not the same?)</td> + <td><code>'Chris' !== 'Ch' + 'ris'</code></td> + </tr> + <tr> + <td><code><</code></td> + <td>Less than</td> + <td><code>10 < 6</code></td> + </tr> + <tr> + <td><code>></code></td> + <td>Greater than</td> + <td><code>10 > 20</code></td> + </tr> + </thead> +</table> + +<h3 id="조건문">조건문</h3> + +<p>함수가 반환되었을때, 자리표시자 메시지(Placeholder Message, 텍스트를 입력할 때 무엇을 입력해야되는지 알려주는 기능 - 역자)를 표시하지 않는 것이 더 좋을 것이라고 본다 . 우리는 사용자의 추측이 옳은지, 틀린지만 보고 적절하게 응답하도록만 할 것이다.</p> + +<p>이 시점에서 이제, 현재 checkGuess()함수를 다음과 같이 수정해보자.</p> + +<pre class="brush: js">function checkGuess() { + var userGuess = Number(guessField.value); + if (guessCount === 1) { + guesses.textContent = 'Previous guesses: '; + } + guesses.textContent += userGuess + ' '; + + if (userGuess === randomNumber) { + lastResult.textContent = 'Congratulations! You got it right!'; + lastResult.style.backgroundColor = 'green'; + lowOrHi.textContent = ''; + setGameOver(); + } else if (guessCount === 10) { + lastResult.textContent = '!!!GAME OVER!!!'; + setGameOver(); + } else { + lastResult.textContent = 'Wrong!'; + lastResult.style.backgroundColor = 'red'; + if(userGuess < randomNumber) { + lowOrHi.textContent = 'Last guess was too low!'; + } else if(userGuess > randomNumber) { + lowOrHi.textContent = 'Last guess was too high!'; + } + } + + guessCount++; + guessField.value = ''; + guessField.focus(); +}</pre> + +<p>꽤 코드가 길다. 각 부분별로 이제 하나하나씩 파헤쳐보자!</p> + +<ul> + <li>2번 줄까지는 userGuess변수를 선언하고, 텍스트 필드에서 입력된 현재 값들을 변수의 값으로 지정한다. 여기서는 빌트인된 <code>Number()</code>메소드(값이 숫자라는 것을 알 수 있다.)로 실행된다.</li> + <li>그러고나서, 처음으로 조건문을 맞딱드린다. (3-5번 줄). 조건문 블록은 조건이 옳은지 그른지에 따라 선택적으로 코드가 실행된다. 함수와 비슷하나, 꼭 그렇지는 않다. 가장 간단한 조건문의 형태는 키워드 <code>if</code>를 사용하고, 괄호가 있고, 중괄호가 있다. 괄호안에는 조건이 삽입된다. 만약 조건문이 옳다면, 중괄호안의 코드들이 실행된다. 거짓이라면, 다음 코드로 넘어가게 된다. 이 코드에서 조건문은 <code>guessCount변수가 1인지 이다.</code> (즉, 현재 플레이어의 게임이 처음인지 아닌지를 판단하는 조건)</li> +</ul> + +<pre class="brush: js">guessCount === 1</pre> + +<p>참이라면, guessess 변수의 텍스트는 "Previous guesses: "가 된다. 그렇지 않다면, 실행되지 않는다.</p> + +<ul> + <li>6번 줄에서는 현재의 userGuess 값에 마지막 guesses 문장을 추가하고, 끝에 공백을 더함으로서 각각의 추측한 수끼리 간격을 두고 보여진다.</li> + <li>다음 블록도 함번 살펴보자(8-24번 줄) + <ul> + <li>첫 <code>if(){ }</code> 는 처음에 지정한 <code>randomNumber</code>과 사용자가 추측한 값(<code>userGuess</code>)이 값은지 본다. 참이라고 계산되면, 플레이어는 숫자를 맞춘것이고 게임을 이기게 된다. 따라서 플레이어에게 초록색, 인포메이션 박스로 축하메시지를 보여주고, 게임을 더할지와 관련된 <code>setGameOver() </code>함수를 불러온다.</li> + <li>이제 <code>else if(){ }</code> 구조를 사용하여 다른 조건문을 추가하게 된다. 이 조건은 사용자가 마지막 순서인지를 계산한다. 참이라면 프로그램은 이전과 같은 블록을 실행한다. 대신 게임을 이기지는 않았기 때문에 축하메시지를 제외된다</li> + <li>마지막 블록은 (the <code>else { }</code>)로 앞선 두 개의 조건이 모두 거짓일 때 실행된다. (i.e. 숫자를 맞추지도 못하고 차례가 남았을 때). 이 경우, 틀렸음을 알려주고, 정답보다 숫자가 큰지 작은지도 계산하여 적절한 메시지를 표시하도록 한다.</li> + </ul> + </li> + <li>함수상의 마지막 3줄(26-28번 줄)은 다음 숫자 추측을 위한 것이다. guessCount 변수에 1을 더함으로, 사용자의 차례가 지나갔음을 안다. (<code>++</code>이란 증감연사자이다. - 1을 더함). 그리고 값에 상관없이 텍스트필드를 공란으로 만들고, 커서를 위치시키므로, 다음값이 입력될 수 있도록 한다.</li> +</ul> + +<h3 id="이벤트">이벤트</h3> + +<p>여기서 우리는 <code>checkGuess()</code> 함수를 잘 구현해 보았지만, 아직 호출하지 않았기 때문에 아무런 역할을 하지 않는다. 실제로는 "Submit guess" 버튼이 눌러져야 호출받도록 할 것이므로, 이벤트를 사용해서 구현할 것이다. 이벤트란 버튼을 클릭하고, 페이지가 로딩되고, 비디오가 실행되는 등 코드가 실행되기 위한 응답으로 브라우저상에서 일어나는 액션이다. 이벤트가 발생하여 발생된 이벤트를 처리하는 것을 <strong>이벤트 리스너(event listeners)</strong>라 하고, 이벤트가 발생했을 때 실행되는 코드 블록을 <strong>이벤트 핸들러(event handlers)</strong>라고 한다.</p> + +<p><code>checkGuess()</code>함수의 중괄호가 끝난뒤, 다음의 코드를 추가해보자.</p> + +<pre class="brush: js">guessSubmit.addEventListener('click', checkGuess);</pre> + +<p><code>이는 guessSubmit</code> 버튼에 이벤트 리스너를 추가하는 과정이다. 두개의 입력(인수)를 가지는 <code>addEventListner</code>메소드이다. 문자열로서 클릭을 처리하는 이벤트이고, 이벤트가 발생했을 때 실행하고자 하는 코드는 <code>checkGuess()</code> 함수이다. 특히, {{domxref("EventTarget.addEventListener", "addEventListener()")}}안에서는 함수의 괄호가 필요없다는 것에 주의하자.</p> + +<p>코드를 저장하고 새로고침해보자, 예제가 실행됨을 볼 수 있다. 아직 게임이 종료되면 실행되는 setGameOver() 함수가 정의되지 않았으므로, 정답을 맞췄을때나 추측에 상관없이 실행되었다면 프로그램의 실행이 멈춰야 한다. 필요한 코드를 작성하고 함수를 추가해보자.</p> + +<h3 id="함수로_프로그램_종료하기">함수로 프로그램 종료하기</h3> + +<p><code>setGameOver()</code>함수를 코드 아래쪽에 추가하고 살펴보자. 자바크스립트 코드의 맨 마지막에 추가하도록 하자.</p> + +<pre class="brush: js">function setGameOver() { + guessField.disabled = true; + guessSubmit.disabled = true; + resetButton = document.createElement('button'); + resetButton.textContent = 'Start new game'; + document.body.appendChild(resetButton); + resetButton.addEventListener('click', resetGame); +}</pre> + +<ul> + <li>2-3번 줄은 텍스트 입력과 버튼의 diabled 속성을 true로 함으로써 작동되지 않도록 한다. 그렇지 않다면 사용자들이 게임이 종료된 후에도 계속 정답을 제출할 것이기 때문에 필수적이다. </li> + <li>4-6번 줄은 새로운 {{htmlelement("button")}} 엘리먼트를 생성하고, "Start new game"라고 표시되게 지정하고 현재의 HTML 아래쪽에 추가하도록 한다.</li> + <li>7번 줄은 새 버튼으로 하여금 이벤트 리스너를 지정하여 클릭되면 <code>resetGame() </code>함수가 실행되도록 한다.</li> +</ul> + +<p>물론 이 함수도 정의해야 한다. 또다시 코드의 가장 아래에 다음 코드를 추가하자.</p> + +<pre class="brush: js">function resetGame() { + guessCount = 1; + + var resetParas = document.querySelectorAll('.resultParas p'); + for (var i = 0 ; i < resetParas.length ; i++) { + resetParas[i].textContent = ''; + } + + resetButton.parentNode.removeChild(resetButton); + + guessField.disabled = false; + guessSubmit.disabled = false; + guessField.value = ''; + guessField.focus(); + + lastResult.style.backgroundColor = 'white'; + + randomNumber = Math.floor(Math.random() * 100) + 1; +}</pre> + +<p>앞서 보는 함수 블록 코드는 게임이 어떻게 시작되고 사용자가 다시 시작할 수 있도록 초기화하는 코드이다.</p> + +<ul> + <li><code>guessCount 변수를 1로 한다.</code></li> + <li>표시된 정보를 모두 초기화한다.</li> + <li>코드상에서 초기화 버튼을 제거한다.</li> + <li>폼 작성을 위해 텍스트를 입력하는 곳을 비워놓고 커서를 위치시킨다.</li> + <li><code>lastResult</code>변수 상의 문장<code> </code>배경색을 제거한다.</li> + <li>임의의 수를 다시 지정함으로, 앞썬 <code>randomNumber</code>와 겹치지 않도록 다시 설정한다.</li> +</ul> + +<p><strong>축하한다! 이제 여기까지 완료됬다면 프로그램이 정상적으로 작동될 것이다.</strong></p> + +<p>이제 살펴볼 것은 코드에서 볼 수 있는 중요한 부분중 하나이다.</p> + +<h3 id="반복문">반복문</h3> + +<p>위 코드상에서 자세히 살펴볼 것 중 하나는 <a href="/en-US/docs/Web/JavaScript/Reference/Statements/for">for</a> 반복문에 관한 부분이다. 반복문은 프로그래머가 지정한 코드의 부분을 조건에 부합할때까지 계속 실행시키는 등 프로그래밍에서 중요한 개념 중 하나이다.</p> + +<p>시작에 앞서, <a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">browser developer tools JavaScript console</a>에 들어가서, 다음을 입력해보자.</p> + +<pre class="brush: js">for (var i = 1 ; i < 21 ; i++) { console.log(i) }</pre> + +<p>어떤 일이 일어났는가? 숫자 1부터 20까지 차례대로 콘솔창에 표시됨을 볼 수 있다.이는 반복이라는 컨셉 때문이다. for 반복문에는 세 개의 입력값(아규먼트)이 있다.</p> + +<ol> + <li><strong>시작값</strong>: 위 코드에서는 1부터 시작하였지만, 프로그래머 임의대로 지정할 수 있다. i 대신 다른 변수를 사용할 수 있지만, 짧고 기억하기 쉬운 관습으로 인해 간단한 알파벳 i가 주로 사용된다.</li> + <li><strong>종료 조건</strong>: 여기서는 <code>i < 21 라고 명시되었다. 이는 i가 21보다 작을때까지 반복이 이루어진다는 말이다. i가 21이 되었을 때, 반복은 종료된다.</code></li> + <li><strong>증감식</strong>: <code>i++이라 명시된 것은 i에 1씩 더하라는 의미이다.반복은 i의 값에 따라 i가 21이 될때까지 반복된다</code>. 여기서는 {{domxref("Console.log", "console.log()")}} 를 사용하여 콘솔창에 반복적으로 i의 값을 출력시키는 간단한 예제를 보였다.</li> +</ol> + +<p>숫자 맞추기 프로그램의 앞선 <code>resetGame()</code> 함수에서 반복문을 한 번 살펴보자.</p> + +<pre class="brush: js">var resetParas = document.querySelectorAll('.resultParas p'); +for (var i = 0 ; i < resetParas.length ; i++) { + resetParas[i].textContent = ''; +}</pre> + +<p>이 코드에서는 {{domxref("Document.querySelectorAll", "querySelectorAll()")}} 메소드를 사용하여 <code><div class="resultParas"></code>안의 모든 문장들의 배열을 변수로 만들고 있다. 그러고 반복을 통해 각각의 배열 원소에 접근하여, 내용을 제거하게 된다.</p> + +<h3 id="객체에_대한_간단한_고찰">객체에 대한 간단한 고찰</h3> + +<p>이제 마지막으로 한단계 더 나아갈 수 있는 부분을 배워보자. <code>var resetButton; </code>아래에 다음 코드를 추가해보자.(코드 위쪽에 있으니 참고하고, 저장까지 해보자)</p> + +<pre class="brush: js">guessField.focus();</pre> + +<p>여기서는 {{domxref("HTMLElement.focus", "focus()")}} 메소드를 통해 자동으로 커서를 페이지가 뜨자마자 {{htmlelement("input")}} 텍스트 필드에 위치시킬 수 있기때문에, 사용자가 처음에 폼 필드를 클릭할 필요없이 바로 글을 쓸 수 있게 된다. 아무것도 아닌 것처럼 보이지만, 사용자에게 굉장히 편리함을 주기 때문에 프로그램에서 좋은 효과를 가져다 준다.</p> + +<p>여기서 이루어지는 일들을 좀 더 자세히 분석해보자. 자바스크립트에서는 모든 것이 객체이다. 객체란 하나의 그룹안에 관계되는 기능(함수)들을 모아놓은 것이다.혼자서 객체를 생성할 수 있겠지만, 아직은 이르기 때문에 나중에 살펴보자. 지금은 간단히 브라우저에 내장된 객체를 사용함으로서 좀 더 많은 일들을 해보는 것에 중점을 두자.</p> + +<p><code><font face="Open Sans, Arial, sans-serif">여기서는, 먼저 HTML의 입력 폼 필드의 정보를 저장하는 </font>guessField</code> 변수를 생성해보자. (다음 코드는 맨 위의 변수 선언문에서 볼 수 있다.)</p> + +<pre class="brush: js">var guessField = document.querySelector('.guessField');</pre> + +<p>이 정보를 얻기 위해, {{domxref("document")}} 객체의 {{domxref("document.querySelector", "querySelector()")}}메소드를 사용한다. <code>querySelector()는 특정 정보(필요한 요소를 추출하는 </code><a href="/en-US/docs/Learn/CSS/Introduction_to_CSS/Selectors">CSS selector</a>)<code>를 가져오는 역할을 한다.</code></p> + +<p><code>이제 </code>{{htmlelement("input")}} 요소의 정보를 담고 있기 때문에, 속성(기본적으로 객체안의 변수나 변수 변경이 없는 경우)과 메소드(기본적으로 객체안의 함수)를 접근할 수 있게 된다. 입력 요소에 이용 가능한 메소드 중 하나가 <code>focus()이며</code>, 따라서 이 메소드를 통해 텍스트 입력에 커서를 가져다 놓을 수 있는 것이다.</p> + +<pre class="brush: js">guessField.focus();</pre> + +<p>폼 요소의 정보를 가지고 있지 않은 변수는 <code>focus()</code> 를 사용할 수 없다. 예를 들어, <code>guesses </code>변수는 {{htmlelement("p")}} 요소의 정보를 가지고 있고, <code>guessCount</code> 변수는 단순한 숫자를 포함하고 있다.</p> + +<h3 id="브라우저_객체로_다루기">브라우저 객체로 다루기</h3> + +<p>이제 브라우저를 객체로서 다뤄보자.</p> + +<ol> + <li>먼저, 브라우저에서 프로그램을 연다</li> + <li>다음 <a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">browser developer tools</a>을 실행하고, 자바스크립트 콘솔창을 활성화한다.</li> + <li> <code>guessField</code>의 입력과 콘솔에서 {{htmlelement("input")}} 요소를 포함한 변수를 보여줄 것이다. 변수를 포함한 실행환경 상에 존재하는 객체이름을 콘솔이 자동으로 완성하는 것도 알아야한다.</li> + <li>다음 코드를 입력하자 + <pre class="brush: js">guessField.value = 'Hello';</pre> + <code>value</code> 속성은 텍스트 필드를 통해 입력되는 현재값을 나타낸다. 커맨드 창에 입력하고 어떤 일이 일어나는지 살펴보자.</li> + <li><code>guesses</code>에 입력하고 반환값을 살펴보자. 콘솔 창에서 변수가 {{htmlelement("p")}} 요소가 있음을 보여줄 것이다.</li> + <li>다음 코드를 입력하자. + <pre class="brush: js">guesses.value</pre> + 브라우저에서 아무런 문장이 없기 때문에, undefined라고 리턴될 것이다.</li> + <li>대신, 다음 코드에서 문자를 변경/추가하기 위해서는 {{domxref("Node.textContent", "textContent")}} 속성을 사용한다. + <pre class="brush: js">guesses.textContent = 'Where is my paragraph?';</pre> + </li> + <li>그러면 이제 다양한 작업을 할 수 있으니, 하나하나 시도해보자. + <pre class="brush: js">guesses.style.backgroundColor = 'yellow'; +guesses.style.fontSize = '200%'; +guesses.style.padding = '10px'; +guesses.style.boxShadow = '3px 3px 6px black';</pre> + 페이지의 모든 요소들을 <code>style</code> 속성을 가지고 있기때문에, 모든 요소에 적용가능한 인라인 CSS 스타일을 포함한 속성을 가진 객체를 포함하고 있음을 알 수 있다. 이는 자바스크립트 상에서 CSS 스타일을 동적으로 지정할 수 있음을 알 수 있다.</li> +</ol> + +<h2 id="결론">결론</h2> + +<p>여기까지 예제를 빌드해보는 과정이었다. 마지막으로 작성된 코드를 실행해보거나,<a href="http://mdn.github.io/learning-area/javascript/introduction-to-js-1/first-splash/number-guessing-game.html">play with our finished version here</a>. 만약 코드가 실행되지 않는다면, <a href="https://github.com/mdn/learning-area/blob/master/javascript/introduction-to-js-1/first-splash/number-guessing-game-start.html">source code</a>를 참고하자.</p> + +<p>{{PreviousMenuNext("Learn/JavaScript/First_steps/What_is_JavaScript", "Learn/JavaScript/First_steps/What_went_wrong", "Learn/JavaScript/First_steps")}}</p> diff --git a/files/ko/learn/javascript/first_steps/arrays/index.html b/files/ko/learn/javascript/first_steps/arrays/index.html new file mode 100644 index 0000000000..0cc11ca43f --- /dev/null +++ b/files/ko/learn/javascript/first_steps/arrays/index.html @@ -0,0 +1,664 @@ +--- +title: Arrays +slug: Learn/JavaScript/First_steps/Arrays +translation_of: Learn/JavaScript/First_steps/Arrays +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/First_steps/Useful_string_methods", "Learn/JavaScript/First_steps/Silly_story_generator", "Learn/JavaScript/First_steps")}}</div> + +<p class="summary">배열은 하나의 변수에 다수의 데이터를 저장하는 좋은 방법이며, 이 글에서 배열의 생성, 검색, 추가, 삭제 등과 같은 내용을 통해 배열에 대해 알아볼 것입니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">선행요소:</th> + <td>기초 컴퓨터 활용지식, HTML, CSS 그리고 JavaScript에 대한 기초 지식.</td> + </tr> + <tr> + <th scope="row">목적:</th> + <td>배열이 무엇인지 이해를 하고 JavaScript에서 어떻게 활용하는지 배운다.</td> + </tr> + </tbody> +</table> + +<h2 id="배열이란">배열이란?</h2> + +<p>배열은 다수의 변수들을 가지고 있는 하나의 객체이다("list-like objects"). 배열 객체는 변수에 저장 해서 사용 할 수 있고, 변수에 저장된 다른 값들과 거의 동일한 방식으로 쓸 수 있다. 일반적인 값들과 배열의 다른점은 내부의 값에 각각 접근할 수 있으며, 루프를 통해 매우 효율적으로 작업이 가능하다는 것이다. 예를 들어 우리가 흔히 보는 영수증의 제품목록, 가격 등이 배열이라고 볼 수 있으며 그 가격들의 총합을 루프를 통하여 구할 수 있다.</p> + +<p>만약 배열이 없다면 다수의 값이 있을 때 각 값의 하나의 변수에 일일이 저장해야 하는 문제가 생길 것이며, 해당 값들을 출력하거나 연산할 때 한땀한땀 개고생 해야한다. 이때문에 코드를 작성하는데 오래걸리며, 비효율적이고 실수를 할 가능성이 높아진다. 오늘 산 물건이 10개 정도라면 값을 더하는데 얼마 걸리지 않겠지만, 100개나 1000개 쯤 구입을 했다면? 잠은 다잔거다.</p> + +<p>이전에 배웠던 것처럼, JavaScript 콘솔에서 몇가지 예제를 통해 배열의 쌩기초 부터 알아보자. 아래에 우리가 제공하는 콘솔이 하나 있다.(<a href="https://mdn.github.io/learning-area/javascript/introduction-to-js-1/variables/index.html">이 콘솔</a>을 새 탭이나 창을 열어서 사용 하거나, 당신이 선호하는 <a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">개발자 콘솔</a>을 사용하면된다.)</p> + +<div class="hidden"> +<h6 id="Hidden_code">Hidden code</h6> + +<pre class="brush: html"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>JavaScript console</title> + <style> + * { + box-sizing: border-box; + } + + html { + background-color: #0C323D; + color: #809089; + font-family: monospace; + } + + body { + max-width: 700px; + } + + p { + margin: 0; + width: 1%; + padding: 0 1%; + font-size: 16px; + line-height: 1.5; + float: left; + } + + .input p { + margin-right: 1%; + } + + .output p { + width: 100%; + } + + .input input { + width: 96%; + float: left; + border: none; + font-size: 16px; + line-height: 1.5; + font-family: monospace; + padding: 0; + background: #0C323D; + color: #809089; + } + + div { + clear: both; + } + + </style> + </head> + <body> + + + </body> + + <script> + var geval = eval; + function createInput() { + var inputDiv = document.createElement('div'); + var inputPara = document.createElement('p'); + var inputForm = document.createElement('input'); + + inputDiv.setAttribute('class','input'); + inputPara.textContent = '>'; + inputDiv.appendChild(inputPara); + inputDiv.appendChild(inputForm); + document.body.appendChild(inputDiv); + + if(document.querySelectorAll('div').length > 1) { + inputForm.focus(); + } + + inputForm.addEventListener('change', executeCode); + } + + function executeCode(e) { + try { + var result = geval(e.target.value); + } catch(e) { + var result = 'error — ' + e.message; + } + + var outputDiv = document.createElement('div'); + var outputPara = document.createElement('p'); + + outputDiv.setAttribute('class','output'); + outputPara.textContent = 'Result: ' + result; + outputDiv.appendChild(outputPara); + document.body.appendChild(outputDiv); + + e.target.disabled = true; + e.target.parentNode.style.opacity = '0.5'; + + createInput() + } + + createInput(); + + </script> +</html></pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_code', '100%', 300, "", "", "hide-codepen-jsfiddle") }}</p> + +<h3 id="배열_만들기">배열 만들기</h3> + +<p>배열은 대괄호로 구성되며 쉼표로 구분 된 항목들을 포함합니다.</p> + +<ol> + <li>쇼핑 목록을 배열에 저장하고 싶다면 다음과 같이하면됩니다. 콘솔에 다음 행을 입력하십시오. + <pre class="brush: js">var shopping = ['bread', 'milk', 'cheese', 'hummus', 'noodles']; +shopping;</pre> + </li> + <li>아래 배열의 각 항목은 문자열이지만 배열의 모든 항목 (문자열, 숫자, 개체, 다른 변수, 심지어 다른 배열)을 저장할 수 있습니다. 동일한 형태의 항목만 넣거나(아래 sequence처럼) 다양한 형태의 항목을 함께 넣을수(아래 random 처럼) 있습니다. 모두 숫자, 문자열 등일 필요는 없습니다. 다음을 입력해보세요. + <pre class="brush: js">var sequence = [1, 1, 2, 3, 5, 8, 13]; +var random = ['tree', 795, [0, 1, 2]];</pre> + </li> + <li>다음으로 넘어가기 전 여러분 마음대로 배열을 만들어 보세요</li> +</ol> + +<h3 id="배열_항목의_접근과_수정">배열 항목의 접근과 수정 </h3> + +<p>그런 다음 <a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/First_steps/Useful_string_methods#Retrieving_a_specific_string_character">문자열의 문자에 접근했던 것</a>과 같은 방법으로 괄호 표기법을 사용하여 배열의 개별 항목을 접근 할 수 있습니다.</p> + +<ol> + <li>콘솔에 다음을 입력하세요: + <pre class="brush: js">shopping[0]; +// returns "bread"</pre> + </li> + <li>단일 배열 항목에 새 값을 제공하여, 배열의 항목을 수정할 수도 있습니다.<br> + 한번 해보세요 : + <pre class="brush: js">shopping[0] = 'tahini'; +shopping; +// shopping will now return [ "tahini", "milk", "cheese", "hummus", "noodles" ]</pre> + + <div class="note"><strong>참고</strong>: 전에도 말했지만, 컴퓨터는 숫자를 셀때 0 부터 시작한다!</div> + </li> + <li>배열 내부의 배열을 다중배열이라고 합니다.대괄호 두개를 함께 연결하여 다른 배열 안에있는 배열 내부의 항목에 접근 할 수 있습니다.예를 들어 <code>무작위</code> 배열(<code>random</code> array) 안의 세 번째 항목 인 배열 내부 항목 중 하나에 접근하려면(앞 섹션 참조) 다음과 같이 할 수 있습니다.: + <pre class="brush: js">random[2][2];</pre> + </li> + <li>다음 단계로 넘어가기 전에 충분히 배열 예제를 연습해보세요.</li> +</ol> + +<h3 id="배열의_갯수_알아내기">배열의 갯수 알아내기</h3> + +<p>{{jsxref("Array.prototype.length","length")}} 속성을 사용해서 배열에 들어 있는 문자열의 갯수를 알아낼 수 있다.(갯수가 얼마나 많이 있던지) 다음을 보자.:</p> + +<pre class="brush: js">sequence.length; +// should return 7</pre> + +<p>다른 용도로 사용되기도 하는데, loop문으로 배열의 모든 항목을 반복적으로 값을 대입하는데 일반적으로 사용한다. 예를 들면:</p> + +<pre class="brush: js">var sequence = [1, 1, 2, 3, 5, 8, 13]; +for (var i = 0; i < sequence.length; i++) { + console.log(sequence[i]); +}</pre> + +<p>다음 article에서 반복문에 대해서 자세히 다루겠지만 다음과 같이 요약할 수 있다.</p> + +<ol> + <li>배열을 반복문으로 돌릴때 item의 시작번호는 0 입니다.</li> + <li>배열의 갯수와 같은 번호일때 반복문을 중단하세요. 어떤 길이의 배열에서도 반복문이 돌지만, 이 경우에선 반복문이 7번 돌고 멈춥니다.(반복문을 끝내기를 원하는 마지막 item의 숫자는 6입니다.)</li> + <li>각각의 item에 대해 <code>console.log()</code>을 사용해 브라우저 콘솔창으로 확인해보세요.</li> +</ol> + +<h2 id="유용한_배열_method">유용한 배열 method</h2> + +<p>이번 섹션에서는 문자열을 배열 항목으로 분할하고, 다시 배열 항목을 문자열로 변환하며 새로운 항목을 배열에 추가할 수 있는 배열 관련 method를 알아봅니다.</p> + +<h3 id="문자열을_배열로_배열을_문자열로_변환하기">문자열을 배열로, 배열을 문자열로 변환하기</h3> + +<p>프로그램을 만들다보면 종종 긴 문자열로 이루어진 원시 데이터를 제공받게 될 것이고, 원시 데이터를 정제하여 더 유용한 데이터를 추출해 테이블 형태로 표시하는 등 작업을 수행해야 합니다. 이러한 작업을 위해 {{jsxref("String.prototype.split()","split()")}} method를 사용할 수 있습니다. {{jsxref("String.prototype.split()","split()")}} method는 사용자가 원하는 매개변수로 문자열을 분리하여 배열로 표현해줍니다.</p> + +<div class="note"> +<p><strong>Note</strong>: 사실 String method이지만, 배열과 함께 사용하기 때문에 여기에 넣었습니다.</p> +</div> + +<ol> + <li>{{jsxref("String.prototype.split()","split()")}} method가 어떻게 작동하는지 살펴봅시다. 우선 콘솔에서 아래와 같은 문자열을 만듭니다: + <pre class="brush: js">var myData = 'Manchester,London,Liverpool,Birmingham,Leeds,Carlisle';</pre> + </li> + <li>콤마로 분리하기 위해 단일 매개변수를 집어넣습니다.: + <pre class="brush: js">var myArray = myData.split(','); +myArray;</pre> + </li> + <li>마지막으로 새로운 배열의 길이를 찾고 이 배열에서 몇 가지 항목을 검색해 봅니다.: + <pre class="brush: js">myArray.length; +myArray[0]; // the first item in the array +myArray[1]; // the second item in the array +myArray[myArray.length-1]; // the last item in the array</pre> + </li> + <li>또한 아래 방법처럼 {{jsxref("Array.prototype.join()","join()")}} method를 사용하여 배열을 다시 문자열로 만들 수 있습니다. : + <pre class="brush: js">var myNewString = myArray.join(','); +myNewString;</pre> + </li> + <li>배열을 문자열로 변환하는 또 다른 방법은 {{jsxref("Array.prototype.toString()","toString()")}} method를 사용하는 것 입니다. <code>toString()</code> 은 <code>join()</code> 과 달리 매개변수가 필요 없어서 더 간단하지만, 제한이 더 많습니다. <code>join()</code> 을 사용하면 다른 구분자를 지정할 수 있습니다. (콤마 말고 다른 매개변수를 사용하여 4단계를 실행 해보세요.) + <pre class="brush: js">var dogNames = ['Rocket','Flash','Bella','Slugger']; +dogNames.toString(); //Rocket,Flash,Bella,Slugger</pre> + </li> +</ol> + +<h3 id="배열에_item을_추가하고_제거하기">배열에 item을 추가하고 제거하기</h3> + +<p>이번엔 배열에 item을 추가하고 제거하는 방법을 알아볼 차례 입니다. 위에서 만든 <code>myArray</code> 를 다시 사용하겠습니다. 섹션을 순서대로 진행하지 않았다면 아래와 같은 배열을 만들어주세요.:</p> + +<pre class="brush: js">var myArray = ['Manchester', 'London', 'Liverpool', 'Birmingham', 'Leeds', 'Carlisle'];</pre> + +<p>먼저, 배열의 맨 끝에 item을 추가하거나 제거하기 위해 각각{{jsxref("Array.prototype.push()","push()")}} and {{jsxref("Array.prototype.pop()","pop()")}} 를 사용할 수 있습니다.</p> + +<ol> + <li>먼저 <code>push()</code> 를 사용합니다. — 배열의 끝에 추가할 item을 반드시 하나 이상 포함해야 한다는 점을 기억하고 아래와 같이 따라해보세요: + + <pre class="brush: js">myArray.push('Cardiff'); +myArray; +myArray.push('Bradford', 'Brighton'); +myArray; +</pre> + </li> + <li>method 호출이 완료되면 배열의 item이 변한것을 확인할 수 있습니다. 새로운 변수에 배열을 저장하려면 아래와 같이 사용합니다.: + <pre class="brush: js">var newLength = myArray.push('Bristol'); +myArray; +newLength;</pre> + </li> + <li>배열의 마지막 item을 제거하는 방법은 <code>pop()</code>으로 매우 간단합니다. 아래와 같이 따라해보세요: + <pre class="brush: js">myArray.pop();</pre> + </li> + <li>method호출이 완료되면 배열에서 item이 제거된 것을 확인할 수 있습니다. 아래 방법을 사용하여 제거될 item을 변수에 저장할 수 있습니다.: + <pre class="brush: js">var removedItem = myArray.pop(); +myArray; +removedItem;</pre> + </li> +</ol> + +<p>{{jsxref("Array.prototype.unshift()","unshift()")}} 와{{jsxref("Array.prototype.shift()","shift()")}}는 <code>push()</code> 와 <code>pop()</code>과 유사하게 동작합니다. 다만, 배열의 맨 끝이 아닌 제일 처음 부분의 item을 추가하거나 제거합니다..</p> + +<ol> + <li>먼저 <code>unshift()</code> 를 사용해봅니다.: + + <pre class="brush: js">myArray.unshift('Edinburgh'); +myArray;</pre> + </li> + <li>이제 <code>shift()</code>를 사용해봅니다.! + <pre class="brush: js">var removedItem = myArray.shift(); +myArray; +removedItem;</pre> + </li> +</ol> + +<h2 id="Active_learning_Printing_those_products!">Active learning: Printing those products!</h2> + +<p>Let's return to the example we described earlier — printing out product names and prices on an invoice, then totaling the prices and printing them at the bottom. In the editable example below there are comments containing numbers — each of these marks a place where you have to add something to the code. They are as follows:</p> + +<ol> + <li>Below the <code>// number 1</code> comment are a number of strings, each one containing a product name and price separated by a colon. We'd like you to turn this into an array and store it in an array called <code>products</code>.</li> + <li>On the same line as the <code>// number 2</code> comment is the beginning of a for loop. In this line we currently have <code>i <= 0</code>, which is a conditional test that causes the <a href="/en-US/Learn/JavaScript/First_steps/A_first_splash#Loops">for loop</a> to stop immediately, because it is saying "stop when <code>i</code> is no longer less than or equal to 0", and <code>i</code> starts at 0. We'd like you to replace this with a conditional test that stops the loop when <code>i</code> is no longer less than the <code>products</code> array's length.</li> + <li>Just below the <code>// number 3</code> comment we want you to write a line of code that splits the current array item (<code>name:price</code>) into two separate items, one containing just the name and one containing just the price. If you are not sure how to do this, consult the <a href="/en-US/docs/Learn/JavaScript/First_steps/Useful_string_methods">Useful string methods</a> article for some help, or even better, look at the {{anch("Converting between strings and arrays")}} section of this article.</li> + <li>As part of the above line of code, you'll also want to convert the price from a string to a number. If you can't remember how to do this, check out the <a href="/en-US/Learn/JavaScript/First_steps/Strings#Numbers_versus_strings">first strings article</a>.</li> + <li>There is a variable called <code>total</code> that is created and given a value of 0 at the top of the code. Inside the loop (below <code>// number 4</code>) we want you to add a line that adds the current item price to that total in each iteration of the loop, so that at the end of the code the correct total is printed onto the invoice. You might need an <a href="/en-US/Learn/JavaScript/First_steps/Math#Assignment_operators">assignment operator</a> to do this.</li> + <li>We want you to change the line just below <code>// number 5</code> so that the <code>itemText</code> variable is made equal to "current item name — $current item price", for example "Shoes — $23.99" in each case, so the correct information for each item is printed on the invoice. This is just simple string concatenation, which should be familiar to you.</li> +</ol> + +<div class="hidden"> +<h6 id="Playable_code">Playable code</h6> + +<pre class="brush: html"><h2>Live output</h2> + +<div class="output" style="min-height: 150px;"> + +<ul> + +</ul> + +<p></p> + +</div> + +<h2>Editable code</h2> + +<p class="a11y-label">Press Esc to move focus away from the code area (Tab inserts a tab character).</p> + +<textarea id="code" class="playable-code" style="height: 410px;width: 95%"> +var list = document.querySelector('.output ul'); +var totalBox = document.querySelector('.output p'); +var total = 0; +list.innerHTML = ''; +totalBox.textContent = ''; +// number 1 + 'Underpants:6.99' + 'Socks:5.99' + 'T-shirt:14.99' + 'Trousers:31.99' + 'Shoes:23.99'; + +for (var i = 0; i <= 0; i++) { // number 2 + // number 3 + + // number 4 + + // number 5 + itemText = 0; + + var listItem = document.createElement('li'); + listItem.textContent = itemText; + list.appendChild(listItem); +} + +totalBox.textContent = 'Total: $' + total.toFixed(2); +</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Reset"> + <input id="solution" type="button" value="Show solution"> +</div> +</pre> + +<pre class="brush: js">var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var code = textarea.value; +var userEntry = textarea.value; + +function updateCode() { + eval(textarea.value); +} + +reset.addEventListener('click', function() { + textarea.value = code; + userEntry = textarea.value; + solutionEntry = jsSolution; + solution.value = 'Show solution'; + updateCode(); +}); + +solution.addEventListener('click', function() { + if(solution.value === 'Show solution') { + textarea.value = solutionEntry; + solution.value = 'Hide solution'; + } else { + textarea.value = userEntry; + solution.value = 'Show solution'; + } + updateCode(); +}); + +var jsSolution = 'var list = document.querySelector(\'.output ul\');\nvar totalBox = document.querySelector(\'.output p\');\nvar total = 0;\nlist.innerHTML = \'\';\ntotalBox.textContent = \'\';\n\nvar products = [\'Underpants:6.99\',\n \'Socks:5.99\',\n \'T-shirt:14.99\',\n \'Trousers:31.99\',\n \'Shoes:23.99\'];\n\nfor(var i = 0; i < products.length; i++) {\n var subArray = products[i].split(\':\');\n var name = subArray[0];\n var price = Number(subArray[1]);\n total += price;\n itemText = name + \' — $\' + price;\n\n var listItem = document.createElement(\'li\');\n listItem.textContent = itemText;\n list.appendChild(listItem);\n}\n\ntotalBox.textContent = \'Total: $\' + total.toFixed(2);'; +var solutionEntry = jsSolution; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); + +// stop tab key tabbing out of textarea and +// make it write a tab at the caret position instead + +textarea.onkeydown = function(e){ + if (e.keyCode === 9) { + e.preventDefault(); + insertAtCaret('\t'); + } + + + if (e.keyCode === 27) { + textarea.blur(); + } +}; + +function insertAtCaret(text) { + var scrollPos = textarea.scrollTop; + var caretPos = textarea.selectionStart; + + var front = (textarea.value).substring(0, caretPos); + var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length); + textarea.value = front + text + back; + caretPos = caretPos + text.length; + textarea.selectionStart = caretPos; + textarea.selectionEnd = caretPos; + textarea.focus(); + textarea.scrollTop = scrollPos; +} + +// Update the saved userCode every time the user updates the text area code + +textarea.onkeyup = function(){ + // We only want to save the state when the user code is being shown, + // not the solution, so that solution is not saved over the user code + if(solution.value === 'Show solution') { + userEntry = textarea.value; + } else { + solutionEntry = textarea.value; + } + + updateCode(); +};</pre> + +<pre class="brush: css">html { + font-family: sans-serif; +} + +h2 { + font-size: 16px; +} + +.a11y-label { + margin: 0; + text-align: right; + font-size: 0.7rem; + width: 98%; +} + +body { + margin: 10px; + background-color: #f5f9fa; +}</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code', '100%', 730, "", "", "hide-codepen-jsfiddle") }}</p> + +<h2 id="실습_Top_5_searches">실습: Top 5 searches</h2> + +<p>A good use for array methods like {{jsxref("Array.prototype.push()","push()")}} and {{jsxref("Array.prototype.pop()","pop()")}} is when you are maintaining a record of currently active items in a web app. In an animated scene for example, you might have an array of objects representing the background graphics currently displayed, and you might only want 50 displayed at once, for performance or clutter reasons. As new objects are created and added to the array, older ones can be deleted from the array to maintain the desired number.</p> + +<p>In this example we're going to show a much simpler use — here we're giving you a fake search site, with a search box. The idea is that when terms are entered in the search box, the top 5 previous search terms are displayed in the list. When the number of terms goes over 5, the last term starts being deleted each time a new term is added to the top, so the 5 previous terms are always displayed.</p> + +<div class="note"> +<p><strong>Note</strong>: In a real search app, you'd probably be able to click the previous search terms to return to previous searches, and it would display actual search results! We are just keeping it simple for now.</p> +</div> + +<p>To complete the app, we need you to:</p> + +<ol> + <li>Add a line below the <code>// number 1</code> comment that adds the current value entered into the search input to the start of the array. This can be retrieved using <code>searchInput.value</code>.</li> + <li>Add a line below the <code>// number 2</code> comment that removes the value currently at the end of the array.</li> +</ol> + +<div class="hidden"> +<h6 id="Playable_code_2">Playable code 2</h6> + +<pre class="brush: html"><h2>Live output</h2> +<div class="output" style="min-height: 150px;"> + +<input type="text"><button>Search</button> + +<ul> + +</ul> + +</div> + +<h2>Editable code</h2> + +<p class="a11y-label">Press Esc to move focus away from the code area (Tab inserts a tab character).</p> + + +<textarea id="code" class="playable-code" style="height: 370px; width: 95%"> +var list = document.querySelector('.output ul'); +var searchInput = document.querySelector('.output input'); +var searchBtn = document.querySelector('.output button'); + +list.innerHTML = ''; + +var myHistory = []; + +searchBtn.onclick = function() { + // we will only allow a term to be entered if the search input isn't empty + if (searchInput.value !== '') { + // number 1 + + // empty the list so that we don't display duplicate entries + // the display is regenerated every time a search term is entered. + list.innerHTML = ''; + + // loop through the array, and display all the search terms in the list + for (var i = 0; i < myHistory.length; i++) { + itemText = myHistory[i]; + var listItem = document.createElement('li'); + listItem.textContent = itemText; + list.appendChild(listItem); + } + + // If the array length is 5 or more, remove the oldest search term + if (myHistory.length >= 5) { + // number 2 + + } + + // empty the search input and focus it, ready for the next term to be entered + searchInput.value = ''; + searchInput.focus(); + } +} +</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Reset"> + <input id="solution" type="button" value="Show solution"> +</div></pre> + +<pre class="brush: css">html { + font-family: sans-serif; +} + +h2 { + font-size: 16px; +} + +.a11y-label { + margin: 0; + text-align: right; + font-size: 0.7rem; + width: 98%; +} + +body { + margin: 10px; + background: #f5f9fa; +}</pre> + +<pre class="brush: js">var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var code = textarea.value; +var userEntry = textarea.value; + +function updateCode() { + eval(textarea.value); +} + +reset.addEventListener('click', function() { + textarea.value = code; + userEntry = textarea.value; + solutionEntry = jsSolution; + solution.value = 'Show solution'; + updateCode(); +}); + +solution.addEventListener('click', function() { + if(solution.value === 'Show solution') { + textarea.value = solutionEntry; + solution.value = 'Hide solution'; + } else { + textarea.value = userEntry; + solution.value = 'Show solution'; + } + updateCode(); +}); + +var jsSolution = 'var list = document.querySelector(\'.output ul\');\nvar searchInput = document.querySelector(\'.output input\');\nvar searchBtn = document.querySelector(\'.output button\');\n\nlist.innerHTML = \'\';\n\nvar myHistory= [];\n\nsearchBtn.onclick = function() {\n if(searchInput.value !== \'\') {\n myHistory.unshift(searchInput.value);\n\n list.innerHTML = \'\';\n\n for(var i = 0; i < myHistory.length; i++) {\n itemText = myHistory[i];\n var listItem = document.createElement(\'li\');\n listItem.textContent = itemText;\n list.appendChild(listItem);\n }\n\n if(myHistory.length >= 5) {\n myHistory.pop();\n }\n\n searchInput.value = \'\';\n searchInput.focus();\n }\n}'; +var solutionEntry = jsSolution; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); + +// stop tab key tabbing out of textarea and +// make it write a tab at the caret position instead + +textarea.onkeydown = function(e){ + if (e.keyCode === 9) { + e.preventDefault(); + insertAtCaret('\t'); + } + + if (e.keyCode === 27) { + textarea.blur(); + } +}; + +function insertAtCaret(text) { + var scrollPos = textarea.scrollTop; + var caretPos = textarea.selectionStart; + + var front = (textarea.value).substring(0, caretPos); + var back = (textarea.value).substring(textarea.selectionEnd, textarea.value.length); + textarea.value = front + text + back; + caretPos = caretPos + text.length; + textarea.selectionStart = caretPos; + textarea.selectionEnd = caretPos; + textarea.focus(); + textarea.scrollTop = scrollPos; +} + +// Update the saved userCode every time the user updates the text area code + +textarea.onkeyup = function(){ + // We only want to save the state when the user code is being shown, + // not the solution, so that solution is not saved over the user code + if(solution.value === 'Show solution') { + userEntry = textarea.value; + } else { + solutionEntry = textarea.value; + } + + updateCode(); +};</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code_2', '100%', 700, "", "", "hide-codepen-jsfiddle") }}</p> + +<h2 id="결론">결론</h2> + +<p>위에 글 읽어보니, 배열이 꽤 유용해 보인다는거 알꺼임; JavaScript에서 배열은 겁나 많이 쓰인다. 배열의 모든 항목 마다 똑같은 작업을 수행하려고 루프(loop)를 돌리니까 같이 알아놓으면 개꿀. 다음 모듈(챕터)에서 루프(loop)에 관한 기초부터 알려줄꺼니까 쫄지 말고 달려. 갈 길이 멀다. 이 모듈은 이제 다 봤어!</p> + +<p>이제 여기서 남은건 이 모듈의 평가뿐이야. 앞에 보여준 글(articles)을 얼마나 이해 했는지 테스트 할꺼임.</p> + +<h2 id="참고">참고</h2> + +<ul> + <li><a href="/en-US/docs/Web/JavaScript/Guide/Indexed_collections">Indexed collections</a> — an advanced level guide to arrays and their cousins, typed arrays.</li> + <li>{{jsxref("Array")}} — the <code>Array</code> object reference page — for a detailed reference guide to the features discussed in this page, and many more.</li> +</ul> + +<p>{{PreviousMenuNext("Learn/JavaScript/First_steps/Useful_string_methods", "Learn/JavaScript/First_steps/Silly_story_generator", "Learn/JavaScript/First_steps")}}</p> + +<h2 id="이번_모듈에서_배울것들">이번 모듈에서 배울것들</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/What_is_JavaScript">JavaScript란 무엇인가?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/A_first_splash">JavaScript를 시작해보자</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/What_went_wrong">뭐가 잘못 되었지? Troubleshooting JavaScript(잘못된 걸 고쳐보자)</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Variables">원하는 정보를 저장하기 — 변</a>수</li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Math">JavaScript의 수학 기초 — 숫자와 연산자</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Strings">문자 다루기 — JavaScript에서의 문자</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Useful_string_methods">유용한 문자 메소드</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Arrays">배열</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Silly_story_generator">평가: 짧은 글 랜덤 생성기</a></li> +</ul> diff --git a/files/ko/learn/javascript/first_steps/index.html b/files/ko/learn/javascript/first_steps/index.html new file mode 100644 index 0000000000..42f6e67418 --- /dev/null +++ b/files/ko/learn/javascript/first_steps/index.html @@ -0,0 +1,60 @@ +--- +title: JavaScript 첫걸음 +slug: Learn/JavaScript/First_steps +tags: + - Article + - Beginner + - CodingScripting + - Guide + - JavaScript + - Landing + - 'l10n:priority' +translation_of: Learn/JavaScript/First_steps +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">첫 과정에서는 "JavaScript가 뭔가요?", "어떻게 생겼나요?", "뭘 할 수 있나요?"와 같은 근본적인 질문을 먼저 해결한 뒤에 JavaScript를 직접 사용해봅니다. 그 다음으로는 변수, 문자열, 숫자, 배열 등 중요한 구성 성분을 하나씩 자세히 알아봅니다.</p> + +<h2 id="준비_과정">준비 과정</h2> + +<p>이번 과정을 시작하기 전에 JavaScript에 대해 몰라도 되지만, HTML, CSS와는 어느 정도 친숙해야 합니다. 우선 다음 과정부터 진행하시는게 좋습니다.</p> + +<ul> + <li><a href="https://developer.mozilla.org/ko/docs/Learn/Getting_started_with_the_web">Web으로 시작하기</a> (아주 기본적인 <a href="/ko/docs/Learn/Getting_started_with_the_web/JavaScript_basics">JavaScript 소개</a>도 포함)</li> + <li><a href="/ko/docs/Learn/HTML/Introduction_to_HTML">HTML 소개</a></li> + <li><a href="/ko/docs/Learn/CSS/Introduction_to_CSS">CSS 소개</a></li> +</ul> + +<div class="note"> +<p><strong>참고</strong>: 파일을 만들 수 없는 컴퓨터나 태블릿, 기타 장치에서 작업을 하신다면 예제 코드의 대부분을 <a href="https://jsbin.com">JSBin</a>이나 <a href="https://thimble.mozilla.org/">Thimble</a> 같은 온라인 코딩 프로그램에서도 시험할 수 있습니다.</p> +</div> + +<h2 id="구성">구성</h2> + +<dl> + <dt><a href="/ko/docs/Learn/JavaScript/First_steps/What_is_JavaScript">JavaScript가 뭔가요?</a></dt> + <dd>MDN의 JavaScript 초급자 과정에 오신 걸 환영합니다! 첫 글은 JavaScript를 넓게 보면서 "뭔가요?", "뭘 하나요?"와 같은 질문을 답변하고, 여러분이 JavaScript에 친숙해지도록 도와드립니다.</dd> + <dt><a href="/ko/docs/Learn/JavaScript/First_steps/A_first_splash">JavaScript에 발 담그기</a></dt> + <dd>JavaScript에 관한 이론과 용도를 약간 배우셨으니, 실용적인 따라해보기와 함께 하는 기초과정 단기 특강을 제공해드리겠습니다. 여기서는 간단한 "숫자 알아맞히기" 게임을 단계별로 차근차근 만들어봅니다.</dd> + <dt><a href="/ko/docs/Learn/JavaScript/First_steps/What_went_wrong">어떤게 잘못됐나요? JavaScript 문제해결</a></dt> + <dd>이전 글에서 "숫자 알아맞히기" 게임을 만든 뒤에, 프로그램이 돌아가지 않는다는 것을 발견하실 겁니다. 두려워하지 마세요. 세 번째 글에서 JavaScript 프로그램의 오류를 찾고 고치는 팁을 배울 수 있습니다.</dd> + <dt><a href="/ko/docs/Learn/JavaScript/First_steps/Variables">필요한 정보 저장하기 — 변수</a></dt> + <dd>앞선 글을 모두 읽으셨으면 이제 JavaScript가 뭔지, 뭘 할 수 있는지, 다른 웹 기술과 함께 어떻게 사용하는지, 주요 기능이 어떻게 생겼는지 등 넓은 윤곽을 그리실 수 있을겁니다. 이제 진짜 기초로 돌아가, JavaScript의 제일 기본적인 구성 요소를 어떻게 사용하는지 알아보겠습니다. 바로 변수입니다.</dd> + <dt><a href="/ko/docs/Learn/JavaScript/First_steps/Math">JavaScript의 기본 수학 — 숫자와 연산자</a></dt> + <dd>여기서는 JavaScript에서의 수학을 이야기하면서, 연산자와 다른 기능을 이리 저리 조합하여 숫자를 여러분의 뜻에 맞게 바꾸는 법을 배웁니다.</dd> + <dt><a href="/ko/docs/Learn/JavaScript/First_steps/Strings">텍스트 다루기 — 문자열</a></dt> + <dd>우리의 시선을 이제 문자열로 돌릴 차례입니다. 프로그래밍에서 텍스트를 일컫는 단어죠. 이번 글에서는 JavaScript를 배울 때 문자열에 대해 알아둬야 하는 것, 예를 들어 문자열 생성, 문자열 안의 따옴표 처리, 문자열 합치기 등을 알아봅니다.</dd> + <dt><a href="/ko/docs/Learn/JavaScript/First_steps/Useful_string_methods">유용한 문자열 메서드</a></dt> + <dd>문자열의 기초를 탐구했으니, 한 단계 더 나아가 문자열의 길이 찾기, 문자열 합치고 나누기, 문자를 다른 문자로 치환하기 등 내장 메서드로 할 수 있는 유용한 작업에 대해 생각해봅니다.</dd> + <dt><a href="/ko/docs/Learn/JavaScript/First_steps/Arrays">배열</a></dt> + <dd>본 과정의 마지막 글에서는 배열에 대해 알아봅니다. 배열은 하나의 변수 이름 아래에 여러 데이터 목록을 저장하는 깔끔한 방법입니다. 배열이 왜 유용한지, 배열을 어떻게 생성하는지, 저장한 데이터를 회수하고, 추가하고, 제거하는 법 등을 배웁니다.</dd> +</dl> + +<h2 id="평가">평가</h2> + +<p>다음 평가를 통해 JavaScript의 기초를 얼마나 이해했는지 시험할 수 있습니다.</p> + +<dl> + <dt><a href="/ko/docs/Learn/JavaScript/First_steps/Silly_story_generator">바보같은 이야기 생성기</a></dt> + <dd>각자 배운 내용을 돌이켜보면서, 바보같은 이야기를 무작위로 만들어내는 앱을 제작해야 합니다. 행운을 빌어요!</dd> +</dl> diff --git a/files/ko/learn/javascript/first_steps/math/index.html b/files/ko/learn/javascript/first_steps/math/index.html new file mode 100644 index 0000000000..b240481e50 --- /dev/null +++ b/files/ko/learn/javascript/first_steps/math/index.html @@ -0,0 +1,422 @@ +--- +title: 자바스크립트의 기본적인 연산 - 숫자와 연산자 +slug: Learn/JavaScript/First_steps/Math +tags: + - 연산자 + - 자바스크립트 + - 진수 +translation_of: Learn/JavaScript/First_steps/Math +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/First_steps/Variables", "Learn/JavaScript/First_steps/Strings", "Learn/JavaScript/First_steps")}}</div> + +<p class="summary">이 장은 자바스크립트의 연산에 대해 다룹니다. 능숙하게 숫자를 다루기 위해 어떻게 {{Glossary("Operator","operators")}} 와 그 외 기능을 사용하는지 알아봅니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">필요조건:</th> + <td>기본적인 커퓨터 지식, HTML과 CSS에 대한 기본적인 이해, JavaScript의 이해</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>자바스크립트 연산에 익숙해지기</td> + </tr> + </tbody> +</table> + +<h2 id="모두가_수학을_좋아합니다">모두가 수학을 좋아합니다</h2> + +<p>좋아요, 아닐수도 있습니다. 일부는 좋아하겠죠. 몇몇 사람들은 구구단을 배울 때부터 싫어했을 겁니다. 그리고 몇몇은 이 사이 어딘가 있겠죠. 그러나 누구도 수학이 삶을 살아가는데 필수적 요소라는건 부정할 수 없을겁니다. 우리가 자바스크립트(혹은 다른 프로그래밍 언어)를 배울때 특히 그렇습니다. 우리가 하는 일의 상당 부분은 수치형 데이터를 처리하고, 값을 계산하거나 하는 일에 의지합니다. </p> + +<p>이 장은 당장 알아야 하는 부분만 다룹니다.</p> + +<h3 id="숫자의_종류">숫자의 종류</h3> + +<p>프로그래밍에서, 우리가 잘 알고있는 십진법 체계라도 당신이 생각한 것보다 복잡합니다.</p> + +<ul> + <li><strong>정수(Integers)</strong>는 10, 400, 혹은 -5 같은 모든 숫자입니다.</li> + <li><strong>실수(Floats)</strong>는 12.5, 6.7786543과 같이 소수점과 소수 자릿수가 있습니다.</li> + <li><strong>실수(Doubles)</strong>는 IEEE 754 표준 부동소수점보다 더 정확한 정밀도를 가지고 있는 특별한 데이터 타입입니다. (<strong>Doubles</strong>은<strong> Floats</strong> 보다 더 많은 소수 자릿수를 표현할 수 있어서 소수점 표현에는 <strong>Doubles</strong>가 더 정확합니다.).</li> +</ul> + +<p>자바스크립트는 심지어 다른 숫자 타입을 지원합니다. 10진수는 10을 기준으로 합니다. (숫자 0~9을 쓴다는 뜻입니다.), 하지만 자바스크립트는 아래와 같은 데이터 타입을 지원합니다.</p> + +<ul> + <li><strong>2진수(Binary)</strong> — 10진수를 0과 1를 이용해 나타내는 데이터 타입입니다.</li> + <li><strong>8진수(Octal)</strong> — 10진수를 0부터 7까지의 수를 이용해 나타내는 데이터 타입입니다.</li> + <li><strong>16진수(Hexadecimal)</strong> — 10진수를 0부터 15까지의 수를 이용해 나타내는 데이터 타입입니다.(1~10, A~F) . <a href="/en-US/Learn/CSS/Introduction_to_CSS/Values_and_units#Hexadecimal_values">CSS의 색상</a>을 지정할 때 쉽게 볼 수 있습니다.</li> +</ul> + +<p><strong>어려워서 힘들다고 느끼기 전에, 잠시 멈추세요!</strong> 시작하기 위해서 우리는 이제부터 10진수만 사용하도록 하겠습니다. 다른 유형에 대해 생각할 필요가 없습니다.</p> + +<p>두 번째 좋은 소식은 다른 프로그래밍 언어와 달리, 자바스크립트는 실수와 정수 모두 {{jsxref("Number")}}라는 하나의 데이터 타입만 사용합니다. 실수와 정수 모두 같은 데이터 타입이기 때문에 하나의 방법으로 동작하게 할 수 있다는 뜻입니다.</p> + +<h3 id="나를_위한_숫자들">나를 위한 숫자들</h3> + + + +<p>우리가 필요한 기본 구문을 다시 익히기 위해 몇 가지 숫자를 빠르게 생각해 봅시다. <a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">developer tools JavaScript console</a> 에 들어가서 아래의 나열된 명령어를 입력해주세요.</p> + +<ol> + <li>먼저, 두 개의 변수를 선언합니다. 그리고 두 개의 변수를 정수와 실수로 초기화해줍니다. 각각 변수명을 콘솔 창에 입력해주세요. 그리고 어떤 값이 나오는지 확인해주세요. + <pre class="brush: js notranslate">var myInt = 5; +var myFloat = 6.667; +myInt; +myFloat;</pre> + </li> + <li>숫자는 따옴표(" 또는 ')가 없습니다. — 계속 하기 전에 여러 개의 변수를 선언하고 숫자를 초기화 해주세요.</li> + <li>우리들의 변수들의 데이터 타입을 확인합니다. 자바스크립트에서는 데이터 타입을 확인하기 위해 {{jsxref("Operators/typeof", "typeof")}} 라는 키워드를 사용합니다. 아래와 같이 입력해 주세요: + <pre class="brush: js notranslate">typeof myInt; +typeof myFloat;</pre> + <code>"number"</code> 는 정수와 실수인 경우에 나옵니다. — 이것들은 정수와 실수가 다른 데이터 타입일 때 보다 다루기 쉽게 해줍니다. 그리고 다른 데이터 타입일 때 다른 방법으로 다뤄야만 합니다. 호우~!</li> +</ol> + +<h2 id="산술_연산자">산술 연산자</h2> + +<p>산술연산자들의 기본적인 용도는 덧셈을 할 때 입니다.</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Operator</th> + <th scope="col">Name</th> + <th scope="col">Purpose</th> + <th scope="col">Example</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>+</code></td> + <td>Addition</td> + <td>두 개의 숫자를 더합니다.</td> + <td><code>6 + 9</code></td> + </tr> + <tr> + <td><code>-</code></td> + <td>Subtraction</td> + <td>왼쪽에 있는 수를 오른쪽 수로 뺍니다.</td> + <td><code>20 - 15</code></td> + </tr> + <tr> + <td><code>*</code></td> + <td>Multiplication</td> + <td>두 개의 숫자를 곱합니다.</td> + <td><code>3 * 7</code></td> + </tr> + <tr> + <td><code>/</code></td> + <td>Division</td> + <td>왼쪽의 숫자를 오른쪽 숫자로 나눠서 몫을 구합니다.</td> + <td><code>10 / 5</code></td> + </tr> + <tr> + <td><code>%</code></td> + <td>Remainder (sometimes called modulo)</td> + <td> + <p>왼쪽의 숫자를 오른쪽 숫자로 나눠서 나머지를 구합니다.</p> + </td> + <td><code>8 % 3</code><br> + ( 2를 반환합니다, 8을 3으로 나눴을 때 몫이 2이기 때문입니다.)</td> + </tr> + </tbody> +</table> + +<div class="note"> +<p><strong>팁</strong>: 연산에 관계된 수를 피연산자라고 부릅니다.<br> + 참고 - {{Glossary("Operand", "operands")}}.</p> +</div> + +<p>아직 수학을 공부할 필요는 없습니다. 하지만 우리는 문법 확인을 해야합니다. 아래의 명령어들을 <a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">developer tools JavaScript console</a> 에 입력해주세요. </p> + +<ol> + <li>아래의 명령어를 콘솔창에 입력해주세요. + <pre class="brush: js notranslate">10 + 7 +9 * 8 +60 % 3</pre> + </li> + <li>You can also try declaring and initializing some numbers inside variables, and try using those in the sums — the variables will behave exactly like the values they hold for the purposes of the sum. For example: + <pre class="brush: js notranslate">var num1 = 10; +var num2 = 50; +9 * num1; +num2 / num1;</pre> + </li> + <li>Last for this section, try entering some more complex expressions, such as: + <pre class="brush: js notranslate">5 + 10 * 3; +num2 % 9 * num1; +num2 + num1 / 8 + 2;</pre> + </li> +</ol> + +<p>Some of this last set of sums might not give you quite the result you were expecting; the below section might well give the answer as to why.</p> + +<h3 id="Operator_precedence">Operator precedence</h3> + +<p>Let's look at the last example from above, assuming that <code>num2</code> holds the value 50 and <code>num1</code> holds the value 10 (as originally stated above):</p> + +<pre class="brush: js notranslate">num2 + num1 / 8 + 2;</pre> + +<p>As a human being, you may read this as <em>"50 plus 10 equals 60"</em>, then <em>"8 plus 2 equals 10"</em>, and finally <em>"60 divided by 10 equals 6"</em>.</p> + +<p>But the browser does <em>"10 divided by 8 equals 1.25"</em>, then <em>"50 plus 1.25 plus 2 equals 53.25"</em>.</p> + +<p>This is because of <strong>operator precedence</strong> — some operators will be applied before others when calculating the result of a sum (referred to as an expression, in programming). Operator precedence in JavaScript is the same as is taught in math classes in school — Multiply and divide are always done first, then add and subtract (the sum is always evaluated from left to right).</p> + +<p>If you want to override operator precedence, you can put parentheses round the parts that you want to be explicitly dealt with first. So to get a result of 6, we could do this:</p> + +<pre class="brush: js notranslate">(num2 + num1) / (8 + 2);</pre> + +<p>Try it and see.</p> + +<div class="note"> +<p><strong>Note</strong>: A full list of all JavaScript operators and their precedence can be found in <a href="/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Operator_precedence">Expressions and operators</a>.</p> +</div> + +<h2 id="Increment_and_decrement_operators">Increment and decrement operators</h2> + +<p>Sometimes you'll want to repeatedly add or subtract one to/from a numeric variable value. This can be conveniently done using the increment (<code>++</code>) and decrement(<code>--</code>) operators. We used <code>++</code> in our "Guess the number" game back in our <a href="/en-US/docs/Learn/JavaScript/Introduction_to_JavaScript_1/A_first_splash">first splash into JavaScript</a> article, when we added 1 to our <code>guessCount</code> variable to keep track of how many guesses the user has left after each turn.</p> + +<pre class="brush: js notranslate">guessCount++;</pre> + +<div class="note"> +<p><strong>Note</strong>: They are most commonly used in <a href="/en-US/docs/Web/JavaScript/Guide/Loops_and_iteration">loops</a>, which you'll learn about later on in the course. For example, say you wanted to loop through a list of prices, and add sales tax to each one. You'd use a loop to go through each value in turn and do the necessary calculation for adding the sales tax in each case. The incrementor is used to move to the next value when needed. We've actually provided a simple example showing how this is done — check it out live, and look at the source code to see if you can spot the incrementors! We'll look at loops in detail later on in the course.</p> +</div> + +<p>Let's try playing with these in your console. For a start, note that you can't apply these directly to a number, which might seem strange, but we are assigning a variable a new updated value, not operating on the value itself. The following will return an error:</p> + +<pre class="brush: js notranslate">3++;</pre> + +<p>So, you can only increment an existing variable. Try this:</p> + +<pre class="brush: js notranslate">var num1 = 4; +num1++;</pre> + +<p>Okay, strangeness number 2! When you do this, you'll see a value of 4 returned — this is because the browser returns the current value, <em>then</em> increments the variable. You can see that it's been incremented if you return the variable value again:</p> + +<pre class="brush: js notranslate">num1;</pre> + +<p>The same is true of <code>--</code> : try the following</p> + +<pre class="brush: js notranslate">var num2 = 6; +num2--; +num2;</pre> + +<div class="note"> +<p><strong>Note</strong>: You can make the browser do it the other way round — increment/decrement the variable <em>then</em> return the value — by putting the operator at the start of the variable instead of the end. Try the above examples again, but this time use <code>++num1</code> and <code>--num2</code>.</p> +</div> + +<h2 id="Assignment_operators">Assignment operators</h2> + +<p>Assignment operators are operators that assign a value to a variable. We have already used the most basic one, <code>=</code>, loads of times — it simply assigns the variable on the left the value stated on the right:</p> + +<pre class="brush: js notranslate">var x = 3; // x contains the value 3 +var y = 4; // y contains the value 4 +x = y; // x now contains the same value y contains, 4</pre> + +<p>But there are some more complex types, which provide useful shortcuts to keep your code neater and more efficient. The most common are listed below:</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Operator</th> + <th scope="col">Name</th> + <th scope="col">Purpose</th> + <th scope="col">Example</th> + <th scope="col">Shortcut for</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>+=</code></td> + <td>Addition assignment</td> + <td>Adds the value on the right to the variable value on the left, then returns the new variable value</td> + <td><code>x = 3;<br> + x += 4;</code></td> + <td><code>x = 3;<br> + x = x + 4;</code></td> + </tr> + <tr> + <td><code>-=</code></td> + <td>Subtraction assignment</td> + <td>Subtracts the value on the right from the variable value on the left, and returns the new variable value</td> + <td><code>x = 6;<br> + x -= 3;</code></td> + <td><code>x = 6;<br> + x = x - 3;</code></td> + </tr> + <tr> + <td><code>*=</code></td> + <td>Multiplication assignment</td> + <td>Multiples the variable value on the left by the value on the right, and returns the new variable value</td> + <td><code>x = 2;<br> + x *= 3;</code></td> + <td><code>x = 2;<br> + x = x * 3;</code></td> + </tr> + <tr> + <td><code>/=</code></td> + <td>Division assignment</td> + <td>Divides the variable value on the left by the value on the right, and returns the new variable value</td> + <td><code>x = 10;<br> + x /= 5;</code></td> + <td><code>x = 10;<br> + x = x / 5;</code></td> + </tr> + </tbody> +</table> + +<p>Try typing some of the above examples into your console, to get an idea of how they work. In each case, see if you can guess what the value is before you type in the second line.</p> + +<p>Note that you can quite happily use other variables on the right hand side of each expression, for example:</p> + +<pre class="brush: js notranslate">var x = 3; // x contains the value 3 +var y = 4; // y contains the value 4 +x *= y; // x now contains the value 12</pre> + +<div class="note"> +<p><strong>Note</strong>: There are lots of <a href="/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Assignment_operators">other assignment operators available</a>, but these are the basic ones you should learn now.</p> +</div> + +<h2 id="Active_learning_sizing_a_canvas_box">Active learning: sizing a canvas box</h2> + +<p>In this exercise, you will manipulate some numbers and operators to change the size of a box. The box is drawn using a browser API called the {{domxref("Canvas API", "", "", "true")}}. There is no need to worry about how this works — just concentrate on the math for now. The width and height of the box (in pixels) are defined by the variables <code>x</code> and <code>y</code>, which are initially both given a value of 50.</p> + +<p>{{EmbedGHLiveSample("learning-area/javascript/introduction-to-js-1/maths/editable_canvas.html", '100%', 520)}}</p> + +<p><strong><a href="https://mdn.github.io/learning-area/javascript/introduction-to-js-1/maths/editable_canvas.html">Open in new window</a></strong></p> + +<p>In the editable code box above, there are two lines marked with a comment that we'd like you to update to make the box grow/shrink to certain sizes, using certain operators and/or values in each case. Let's try the following:</p> + +<ul> + <li>Change the line that calculates x so the box is still 50px wide, but the 50 is calculated using the numbers 43 and 7 and an arithmetic operator.</li> + <li>Change the line that calculates y so the box is 75px high, but the 75 is calculated using the numbers 25 and 3 and an arithmetic operator.</li> + <li>Change the line that calculates x so the box is 250px wide, but the 250 is calculated using two numbers and the remainder (modulo) operator.</li> + <li>Change the line that calculates y so the box is 150px high, but the 150 is calculated using three numbers and the subtraction and division operators.</li> + <li>Change the line that calculates x so the box is 200px wide, but the 200 is calculated using the number 4 and an assignment operator.</li> + <li>Change the line that calculates y so the box is 200px high, but the 200 is calculated using the numbers 50 and 3, the multiplication operator, and the addition assignment operator.</li> +</ul> + +<p>Don't worry if you totally mess the code up. You can always press the Reset button to get things working again. After you've answered all the above questions correctly, feel free to play with the code some more or create your own challenges.</p> + +<h2 id="Comparison_operators">Comparison operators</h2> + +<p>Sometimes we will want to run true/false tests, then act accordingly depending on the result of that test — to do this we use <strong>comparison operators</strong>.</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Operator</th> + <th scope="col">Name</th> + <th scope="col">Purpose</th> + <th scope="col">Example</th> + </tr> + <tr> + <td><code>===</code></td> + <td>Strict equality</td> + <td>Tests whether the left and right values are identical to one another</td> + <td><code>5 === 2 + 4</code></td> + </tr> + <tr> + <td><code>!==</code></td> + <td>Strict-non-equality</td> + <td>Tests whether the left and right values <strong>not</strong> identical to one another</td> + <td><code>5 !== 2 + 3</code></td> + </tr> + <tr> + <td><code><</code></td> + <td>Less than</td> + <td>Tests whether the left value is smaller than the right one.</td> + <td><code>10 < 6</code></td> + </tr> + <tr> + <td><code>></code></td> + <td>Greater than</td> + <td>Tests whether the left value is greater than the right one.</td> + <td><code>10 > 20</code></td> + </tr> + <tr> + <td><=</td> + <td>Less than or equal to</td> + <td>Tests whether the left value is smaller than or equal to the right one.</td> + <td><code>3 <= 2</code></td> + </tr> + <tr> + <td>>=</td> + <td>Greater than or equal to</td> + <td>Tests whether the left value is greater than or equal to the right one.</td> + <td><code>5 >= 4</code></td> + </tr> + </thead> +</table> + +<div class="note"> +<p><strong>Note</strong>: You may see some people using <code>==</code> and <code>!=</code> in their tests for equality and non-equality. These are valid operators in JavaScript, but they differ from <code>===</code>/<code>!==</code>. The former versions test whether the values are the same but not whether the values' datatypes are the same. The latter, strict versions test the equality of both the values and their datatypes. The strict versions tend to result in fewer errors, so we recommend you use them.</p> +</div> + +<p>If you try entering some of these values in a console, you'll see that they all return <code>true</code>/<code>false</code> values — those booleans we mentioned in the last article. These are very useful, as they allow us to make decisions in our code, and they are used every time we want to make a choice of some kind. For example, booleans can be used to:</p> + +<ul> + <li>Display the correct text label on a button depending on whether a feature is turned on or off</li> + <li>Display a game over message if a game is over or a victory message if the game has been won</li> + <li>Display the correct seasonal greeting depending what holiday season it is</li> + <li>Zoom a map in or out depending on what zoom level is selected</li> +</ul> + +<p>We'll look at how to code such logic when we look at conditional statements in a future article. For now, let's look at a quick example:</p> + +<pre class="brush: html notranslate"><button>Start machine</button> +<p>The machine is stopped.</p> +</pre> + +<pre class="brush: js notranslate">var btn = document.querySelector('button'); +var txt = document.querySelector('p'); + +btn.addEventListener('click', updateBtn); + +function updateBtn() { + if (btn.textContent === 'Start machine') { + btn.textContent = 'Stop machine'; + txt.textContent = 'The machine has started!'; + } else { + btn.textContent = 'Start machine'; + txt.textContent = 'The machine is stopped.'; + } +}</pre> + +<p>{{EmbedGHLiveSample("learning-area/javascript/introduction-to-js-1/maths/conditional.html", '100%', 100)}}</p> + +<p><strong><a href="https://mdn.github.io/learning-area/javascript/introduction-to-js-1/maths/conditional.html">Open in new window</a></strong></p> + +<p>You can see the equality operator being used just inside the <code>updateBtn()</code> function. In this case, we are not testing if two mathemetical expressions have the same value — we are testing whether the text content of a button contains a certain string — but it is still the same principle at work. If the button is currently saying "Start machine" when it is pressed, we change its label to "Stop machine", and update the label as appropriate. If the button is currently saying "Stop machine" when it is pressed, we swap the display back again.</p> + +<div class="note"> +<p><strong>Note</strong>: Such a control that swaps between two states is generally referred to as a <strong>toggle</strong>. It toggles between one state and another — light on, light off, etc.</p> +</div> + +<h2 id="Summary">Summary</h2> + +<p>In this article we have covered the fundamental information you need to know about numbers in JavaScript, for now. You'll see numbers used again and again, all the way through your JavaScript learning, so it's a good idea to get this out of the way now. If you are one of those people that doesn't enjoy math, you can take comfort in the fact that this chapter was pretty short.</p> + +<p>In the next article, we'll explore text and how JavaScript allows us to manipulate it.</p> + +<div class="note"> +<p><strong>Note</strong>: If you do enjoy math and want to read more about how it is implemented in JavaScript, you can find a lot more detail in MDN's main JavaScript section. Great places to start are our <a href="/en-US/docs/Web/JavaScript/Guide/Numbers_and_dates">Numbers and dates</a> and <a href="/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators">Expressions and operators</a> articles.</p> +</div> + +<p>{{PreviousMenuNext("Learn/JavaScript/First_steps/Variables", "Learn/JavaScript/First_steps/Strings", "Learn/JavaScript/First_steps")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/What_is_JavaScript">What is JavaScript?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/A_first_splash">A first splash into JavaScript</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/What_went_wrong">What went wrong? Troubleshooting JavaScript</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Variables">Storing the information you need — Variables</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Math">Basic math in JavaScript — numbers and operators</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Strings">Handling text — strings in JavaScript</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Useful_string_methods">Useful string methods</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Arrays">Arrays</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Silly_story_generator">Assessment: Silly story generator</a></li> +</ul> diff --git a/files/ko/learn/javascript/first_steps/silly_story_generator/index.html b/files/ko/learn/javascript/first_steps/silly_story_generator/index.html new file mode 100644 index 0000000000..a6f2318602 --- /dev/null +++ b/files/ko/learn/javascript/first_steps/silly_story_generator/index.html @@ -0,0 +1,192 @@ +--- +title: Silly story generator +slug: Learn/JavaScript/First_steps/Silly_story_generator +translation_of: Learn/JavaScript/First_steps/Silly_story_generator +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenu("Learn/JavaScript/First_steps/Arrays", "Learn/JavaScript/First_steps")}}</div> + +<p class="summary">이 모듈에서 배운 지식들을 바탕으로 랜덤하게 꾸며진 이야기(silly stories)가 만들어지는 재미있는 앱을 만들어 볼거에요. 즐겨봅시다!!</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">선행요소:</th> + <td>이 평가에 시도하기 전에 이 모듈에서 배운 항목을 모두 수행해봐야 합니다.</td> + </tr> + <tr> + <th scope="row">목적:</th> + <td>변수, 숫자, 연산자, 문자열 및 배열 같은 자바스크립트의 기본항목들에 대한 전반적인 이해를 테스트합니다.</td> + </tr> + </tbody> +</table> + +<h2 id="시작하기">시작하기</h2> + +<p>이 평가하기(assements)를 시작하기 전에, 아래와 같은 것을 해야 합니다:</p> + +<ul> + <li>HTML 예제 파일이 있는 사이트(<a href="https://github.com/mdn/learning-area/blob/master/javascript/introduction-to-js-1/assessment-start/index.html">grab the HTML file</a>)로 이동하여 파일을 복사하여 자기 컴퓨터에 새 디렉토리를 만들고 파일이름 <code>index.html</code> 로 저장합니다. 이 안에는 예제를 위한 CSS가 포함되어 있습니다.</li> + <li>또 다른 가공 전의 텍스트가 있는 사이트 (<a href="https://github.com/mdn/learning-area/blob/master/javascript/introduction-to-js-1/assessment-start/raw-text.txt">page containing the raw text</a>) 로 가서 별도의 브라우저 탭으로 열어 놓으세요. 이것은 나중에 필요합니다.</li> +</ul> + +<p>위 방법 대신에, 여러분은 테스트에 <a href="http://jsbin.com/">JSBin</a> 또는 <a href="https://glitch.com/">Glitch</a> 같은 사이트를 이용할 수 있습니다. 이 온라인 에디터들 내부에 HTML, CSS 그리고 JavaScript를 붙여넣을 수 있습니다. 만약 당신이 사용하는 온라인 에디터가 Javascript 패널(또는 탭)을 갖고 있지 않다면, 자유롭게 HTML 페이지 내부에 <code><script></code> 엘리멘트를 넣을 수 있습니다.</p> + +<div class="note"> +<p><strong>Note</strong>: 만약 평가가 막힌다면, 우리에게 도움을 요청하세요— 이 페이지 밑에 {{anch("Assessment or further help")}} 섹션을 보세요.</p> +</div> + +<h2 id="프로젝트에_대한_간략한_설명">프로젝트에 대한 간략한 설명</h2> + +<p>이제 프로젝트 시작을 위해 가공하지 않은 HTML/CSS 그리고 몇몇 텍스트를 만들고 확인했습니다. 이제 아래와 같은 기능을 하는 프로그램을 만들기 위해 JavaScript를 코딩해야 합니다.</p> + +<ul> + <li>"랜덤한 이야기 만들기('Generate random story') 버튼를 누를 때 마다 꾸며진 이야기(silly stories)를 만들어야 합니다.</li> + <li>"Enter custome name" 필드에 값이 입력되어있지 않을 경우 기본 이름을 Bob으로 지정합니다. "랜덤한 이야기 만들기('Generate random story')" 버튼을 클릭 하면 아래 사진에서 "Chris saw the ~.." 로 시작하는 문장이 "Bob saw the ~.."로 표시되게 합니다.</li> + <li>"랜덤한 이야기 만들기('Generate random story')" 을 클릭하면 프로그램이 "US", "UK" 라디오 체크버튼을 확인하여 각 국가에 맞는 온도, 수량, 무게 등 단위를 설정하세요. 아래 사진의 예를 들면 "~ weights 300 pounds, and ~" 부분이 해당됩니다.</li> + <li>"랜덤한 이야기 만들기('Generate random story')" 을 누르면 꾸며진 이야기('silly stories')가 랜덤하게 계속 만들어지게 하세요.</li> +</ul> + +<p>이 스크린샷은 프로그램 출력의 예시 입니다:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13667/assessment-1.png" style="border-style: solid; border-width: 1px; display: block; margin: 0px auto;"></p> + +<p>더 많은 아이디어를 얻으려면, 완성된 예(<a href="http://mdn.github.io/learning-area/javascript/introduction-to-js-1/assessment-finished/">have a look at the finished example</a> )를 참고하세요(소스코드는 엿보기 없기!)</p> + +<h2 id="완료하기">완료하기</h2> + +<p>이번 섹션에선 프로젝트를 어떻게 진행해야 하는지 자세하게 설명합니다.</p> + +<p>기본 설정:</p> + +<ol> + <li><code>index.html</code> <font face="Open Sans">파</font>일과 같은 디렉토리에 <code>main.js</code> 라는 이름의 파일을 새로 만듭니다.</li> + <li>HTML 파일(<code>index.html</code>)에 <a href="https://developer.mozilla.org/ko/docs/Web/HTML/Element/script"><script></a> 엘리먼트를 삽입하여 <code>main.js</code> 를 참조하도록 외부 자바스크립트 파일(<code>main.js</code>)을 적용합니다. <code></body></code> 태그 바로 앞에 배치하세요.</li> +</ol> + +<p>초기 변수와 함수:</p> + +<ol> + <li> + <p>가공 전의 텍스트 파일에서, "1. COMPLETE VARIABLE AND FUNCTION DEFINITIONS" 바로 밑의 코드를 모두 복사해서 <code>main.js</code> 파일의 맨 위에 붙여넣습니다. 이 내용은 세 개의 변수 제공하는데, <code>customName</code> 변수는 "Enter custom name" 텍스트 필드 값을 저장하고, <code>randomize</code> 변수에는 "Generate random story" 버튼 오브젝트를 저장하고, HTML 바디에 끝에 있는 클래스가 <code>story</code>인 <a href="https://developer.mozilla.org/ko/docs/Web/HTML/Element/p"><p></a> 엘리먼트는 story 변수에 저장하며 해당 엘리먼트에는 랜덤한 이야기가 복사됩니다. 또한, randomValueFromArray() 함수는 배열을 가져와서 배열이 가진 항목 중 하나를 랜덤하게 반환합니다.</p> + </li> + <li> + <p>가공전 텍스트 파일의 두번째 섹션 "2. RAW TEXT STRINGS"에는 프로그램에 자동으로 입력되어 랜덤 이야기 엘리먼트에 출력하는 문자열이 포함되어 있습니다. <code>main.js</code> 에 아래 설명대로 변수를 만듭니다:</p> + + <ol> + <li>먼저 <code>storyText</code>변수에 가장 긴 문자열("It was 94 fahrenheit outside, so ~~" 로 시작하는 문장)을 저장합니다.</li> + <li><code>insertX</code> 배열에 세 개의 문자열 집단의 첫번째(Willy the Goblin, Big Daddy, Father Christmas)를 저장합니다.</li> + <li><code>insertY</code> 배열에 세 개의 문자열 집단의 두번째(the soup kitchen, Disneyland, the White House)을 저장합니다.</li> + <li><code>insertZ</code> 배열에 세 개의 문자열 집단의 세번째(spontaneously combusted, melted into a puddle on the sidewalk, turned into a slug and crawled away)를 저장합니다.</li> + </ol> + </li> +</ol> + +<p>이벤트 핸들러와 완성되지 않은 함수 정리:</p> + +<ol> + <li>가공전 텍스트 파일("raw text file")로 돌아가자.</li> + <li>"3. EVENT LISTENER AND PARTIAL FUNCTION DEFINITION" 밑의 코드를 복사하고, <code>main.js</code> 파일의 맨 밑에다 붙여 넣으세요: + <ul> + <li><code>randomize</code> 변수에 클릭 이벤트 리스너를 추가하세요. 그러면 버튼이 클릭되었을 때, <code>result()</code> 함수가 실행됩니다.</li> + <li>코드에 부분적으로 완료된 <code>result()</code> 함수를 추가하세요. 이 평가의 뒤 부분에서 함수가 완성되고 정상적으로 동작하도록 내용을 추가할 것입니다.</li> + </ul> + </li> +</ol> + +<p><code>result()</code> 함수 완성하기: </p> + +<ol> + <li><code>newStory</code>라 불리는 새 변수를 만들고, 이것의 값(value)를 <code>storyText</code> 와 똑같이 설정하세요. 이것은 버튼을 누르고 함수가 수행(run)될 때 마다 새 이야기('story')가 랜덤하게 만들어 질 수 있게 합니다. <code>storyText</code>를 직접 변경했다면, 새로운 이야기('story')를 한번만 만들 수 있습니다(함수를 통해서 하지 않으면 정적인 값만 유지한다는 의미).</li> + <li>세 개의 새로운 변수 <code>xItem</code>, <code>yItem</code>, 와 <code>zItem</code>를 만들고 이 세 개의 변수는 <code>randomValueFromArray()</code> 를 반환 결과인 세개의 배열과 같도록 만듭니다(각 경우의 호출 결과는 각 배열에 임의의 아이템). 예를 들어 <code>randomValueFromArray(insertX) </code>함수를 호출하면 <code>insertX</code> 에서 문자열의 하나를 랜덤하게 가질 수 있다.</li> + <li>그 다음으로 <code>newStory</code> 문자열에 있는 세 개의 placeholders— <code>:insertx:</code>, <code>:inserty:<font face="Arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;">, </span></font></code><code>:insertz:</code> —저장된 <code>xItem</code>, <code>yItem </code>와 <code>zItem</code> 문자열을 이용하여 로 변환하세요. 여기서 특정 문자열 함수가 도움될 것입니다. 이 함수는 각 경우에 <code>newStory</code>와 같게되며(대입), 호출 시 마다 <code>newStory</code> 의 원래 값과 동일하지만 대체 될 수 있습니다(랜덤으로 값이 변경되는 것을 표현하는 것으로 추정됨) 그러므로 버튼이 눌러질때마다, 이 placeholder는 꾸며진('silly') 문자열로 랜덤하게 교체되게 됩니다. 추가적인 힌트로, 이 문제의 함수는 하위 문자열에서 찾아진 첫번째 인스턴스만 변경되므로, 아마도 두번 이상 이 함수를 호출해야 할 수도 있습니다.</li> + <li>첫번째 <code>if</code> 블록에서, <code>newStory</code> 의 'Bob'이라는 이름을 <code>name</code> 변수를 사용하여 변환하는 함수를 추가하세요. 이 블록에서 말하는 내용은 "만약 <code>customName</code> 텍스트 입력에 값이 들어가 있다면, 이야기속의 Bob을 사용자가 정의한 이름으로 바꾸세요" 라는 의미입니다.</li> + <li>두번째 <code>if</code> 블록에서는 <code>uk</code> 라디오 버튼이 선택되었는지 확인합시다. <code>uk</code> 라디오 버튼이 눌려졌다면, 이야기('story') 상의 무게('weight')와 온도('temperature') 값 들인 파운드('pounds')와 화씨온도(Fahrenheit) 를 'stones'과 섭씨온도('centigrade')를 바꾸어야 합니다. 필요한 것은 아래와 같습니다: + <ol> + <li>파운드(pound)를 stone, 화씨온도(Fahrenheit) 를 섭씨온도(centigrade)로 변환하는 공식을 참조하라.</li> + <li> <code>weight</code> 변수를 정의하는 라인에서는, 300를 300 파운드를 stones 변환하라. 변환 결과값을 <code>Math.round()</code> 를 실행한 결과값 끝에 <code>' stone'</code> 을 결합한다(문자열 더하기 연산 또는 concat())</li> + <li> <code>temperature</code> 변수를 정의하는 라인에서는, 94를 화씨(Fahrenheit) 94도를 섭씨온도(centigrade)로 변환하라. 변환 결과값을 <code>Math.round()</code> 를 실행한 결과값 끝에 <code>' centigrade'</code>을 결합한다(문자열 더하기 연산 또는 concat())</li> + <li>두 변수 정의 바로 밑에, '94 화씨온도('farenheit')로 <code>temperature</code> 변수의 내용을 변환하는 것과, '300 pounds'을 <code>weight</code> 변수의 내용을 바꾸는 두줄의 문자열 변환라인을 추가한다 .</li> + </ol> + </li> + <li>마지막으로, 함수의 끝 두 줄에 <code>story</code> 변수의 <code>textContent</code> 속성(property)을 <code>newStory</code>와 같게 만드세요.</li> +</ol> + +<h2 id="힌트와_팁">힌트와 팁</h2> + +<ul> + <li>JavaScript 내용 외에는 HTML을 수정할 필요가 없습니다.</li> + <li>만약 JavaScript가 정상적으로 HTML에 적용되었는지 의심스럽다면, 일시적으로 JavaScript의 내용을 지우고, 단순하고 짧은 효과가 명확한 내용을 추가해서, 저장하고 새로고침을 해보세요. 아래 예제는 {{htmlelement("html")}} 의 배경을 빨강색으로 바꿉니다 — 정상적으로 JavaScript가 적용되었다면 브라우저 전체 윈도우가 빨강색으로 바뀌게 될겁니다: + <pre class="brush: js notranslate">document.querySelector('html').style.backgroundColor = 'red';</pre> + </li> + <li><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round">Math.round()</a> 는 가장 가까운 정수로 단순하게 반올림한 결과를 반환하는 JavaScript 내장함수 입니다. </li> + <li>변환이 필요한 세 개의 문장이 문제 있습니다. 아마도 <code>replace()</code> 함수를 반복적으로 실행 하거나 정규 표현식을 사용할 수 있습니다. 예를 들어 <code>var text = 'I am the biggest lover, I love my love'; text.replace(/love/g,'like');</code> 를 실행하면 인스턴스의 'love' 는 'like' 로 모두 바뀌게 될겁니다. 기억하세요, 문자열은 변하지 않습니다!(문자열은 새 변경할 수 없으며, 새 문자열이 생성되고 그 생성된 결과를 인스턴스가 갖게됨을 표현한 것으로 추정)</li> +</ul> + +<h2 id="평가_또는_추가_도움">평가 또는 추가 도움</h2> + +<p>만약 작업을 평가하길 원하거나 풀이가 막혀서 도움을 원하면:</p> + +<ol> + <li>온라인 공유가 가능한 <a href="https://codepen.io/">CodePen</a>, <a href="https://jsfiddle.net/">jsFiddle</a>, 또는 <a href="https://glitch.com/">Glitch</a> 같은 에디터에 작업한 것을 올려 두세요.</li> + <li>평가 또는 도움을 요청을 <a href="https://discourse.mozilla.org/c/mdn/learn">MDN Discourse forum Learning category</a> 에 포스트를 쓰세요. 당신의 글은 아래를 포함해야 합니다: + <ul> + <li>"Assessment wanted for Silly story generator"와 같은 서술적인 제목.</li> + <li>이미 시도해본 것에 대한 상세내용과 우리가 어떻게 하길 원하는 지.<br> + 예. 만약 당신이 풀이가 막히고 도움이 필요하다거나, 평가를 원한다는 것을.</li> + <li>평가를 받고 싶거나 도움이 필요한 예제를 갖고 있는 공유가능한 온라인 에디터 링크. (위에 1단계에서 언급한 것). 이것은 좋은 습관입니다. 그들의 코드를 보지못한다면 도움을 주기는 굉장히 어렵습니다.</li> + <li>실제 작업 또는 평가 페이지 링크, 그래야 우리가 당신이 도움받길 원하는 것을 찾을 수 있어요.</li> + </ul> + </li> +</ol> + +<p>{{PreviousMenu("Learn/JavaScript/First_steps/Arrays", "Learn/JavaScript/First_steps")}}</p> + +<h2 id="이_모듈에서">이 모듈에서</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/What_is_JavaScript">What is JavaScript?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/A_first_splash">A first splash into JavaScript</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/What_went_wrong">What went wrong? Troubleshooting JavaScript</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Variables">Storing the information you need — Variables</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Math">Basic math in JavaScript — numbers and operators</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Strings">Handling text — strings in JavaScript</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Useful_string_methods">Useful string methods</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Arrays">Arrays</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Silly_story_generator">Assessment: Silly story generator</a></li> +</ul> + +<div id="dicLayer" style=""> +<div id="dicLayerContents"><dicword style="user-select: text;">What is JavaScript?</dicword><dicword style="user-select: text;"><dicimg id="play" style="background-image: url(chrome-extension://bmbdcffdhebhecemcchbkfnjlmdiiepe/play.gif);"></dicimg> <input>Eng<dicimg id="copy" style="background-image: url(chrome-extension://bmbdcffdhebhecemcchbkfnjlmdiiepe/copy.png);" title="copy"></dicimg></dicword><br> +<br> +<br> +<br> +자바 스크립트 란?</div> + +<div id="dicLayerSub"></div> +</div> + +<div id="dicRawData" style="display: none;">{"mean":["what<br/><br/>[대명사, 한정사]\n\t\t \t\t(의문문에서) 무엇; 몇; 어떤, 무슨\n\n\t\t 참조 which","be<br/><br/>[동사]\n\t\t there is/are\n\t\t \t\t있다, 존재하다","script<br/><br/>[명사]\n\t\t \t\t(연극영화방송강연 등의) 대본[원고]","is<br/><br/>참조 be","Java Script<br/><br/>(컴퓨터)\n\t\t \t\t자바 스크립트 ((미국 넷스케이프 커뮤니케이션스가 개발한 스크립트 언어))","TypeScript<br/><br/>[Proper noun] labelenscripting language A scripting programming language that is a strict superset of JavaScript and used to implement interactive features of Web pages."],"word":"What is JavaScript","soundUrl":"https://dict-dn.pstatic.net/v?_lsu_sa_=39682b535d673a26a89ab1563094c4fead4462b51a0a6f796ee2097e5bbb6bb1195cb75069a5ad7d792362a5c22ac0e7677a456c5837d53ff458f869cb3070278c86c07296cca27ab57925fedb326fd11c977e7d7a242a0e57b9d7f96c3e974376013120f37159780b34a104ca6074c614d78e8a098ad60cfcbe8ec73ef6b8cb","phoneticSymbol":""}</div> + +<div id="dicLayerLoader" style="top: 5596px; left: 281px;"></div> + +<div id="dicLayer"> +<div id="dicLayerContents"></div> + +<div id="dicLayerSub"></div> +</div> + +<div id="dicRawData" style="display: none;"></div> + +<div id="dicLayerLoader"></div> + +<div id="dicLayer"> +<div id="dicLayerContents"></div> + +<div id="dicLayerSub"></div> +</div> + +<div id="dicRawData" style="display: none;"></div> + +<div id="dicLayerLoader"></div> diff --git a/files/ko/learn/javascript/first_steps/strings/index.html b/files/ko/learn/javascript/first_steps/strings/index.html new file mode 100644 index 0000000000..0e24be92a8 --- /dev/null +++ b/files/ko/learn/javascript/first_steps/strings/index.html @@ -0,0 +1,294 @@ +--- +title: 문자열 다루기 — 문자열 +slug: Learn/JavaScript/First_steps/Strings +tags: + - 가이드 + - 강좌 + - 따옴표 + - 문자열 + - 자바스크립트 + - 초보자 + - 코딩 +translation_of: Learn/JavaScript/First_steps/Strings +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/First_steps/Math", "Learn/JavaScript/First_steps/Useful_string_methods", "Learn/JavaScript/First_steps")}}</div> + +<p class="summary">다음으로, 프로그래밍에서 어떤 텍스트가 호출되는지 문자열에 대해 알아볼까요? 이 게시물에서는 문자열 작성, 문자열의 따옴표 이스케이프 및 문자열 결합과 같이 JavaScript를 배울 때 문자열에 대해 알아야 할 모든 일반적인 사항을 살펴보겠습니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">선결요건:</th> + <td>기본 컴퓨터 활용능력, HTML 및 CSS에 대한 기본적인 이해, JavaScript에 대한 기초적인 이해.</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>JavaScript에서 문자열의 기초에 대해 익숙해지기.</td> + </tr> + </tbody> +</table> + +<h2 id="단어의_힘">단어의 힘</h2> + +<p>단어는 인간이 커뮤니케이션 함에 있어 커다란 하나의 부분이라고 할 수 있기에 매우 중요합니다. 웹은 사람들이 정보를 교환하고 공유할 수 있도록 설계된 텍스트 기반의 매체이므로, 웹에 표시되는 단어를 제어하는 것이 유용합니다. {{glossary ( "HTML")}}은 텍스트에 구조와 의미를 제공하며, {{glossary ( "CSS")}}는 텍스트에 스타일(일종의 디자인)을 적용할 수 있게 해주며, JavaScript는 문자열을 조작하기 위한 여러 가지 기능 (텍스트 레이블을 표시하고 용어를 원하는 순서로 정렬하는) 등 다양한 작업을 수행할 수 있습니다.</p> + + + +<p>지금까지 우리가 여러분에게 보여 줬던 거의 모든 프로그램은 문자열 조작과 관련이 있습니다.</p> + +<h2 id="문자열_—_기초">문자열 — 기초</h2> + +<p>문자열은 숫자와 유사하게 다루어지지만, 더 깊게 파고들면 눈에 띄는 차이점을 발견하기 시작할 것입니다. 먼저 몇 가지 기본 라인을 콘솔에 입력하여 우리와 친숙하게 만드는 것으로 시작하겠습니다. <a href="https://mdn.github.io/learning-area/javascript/introduction-to-js-1/variables/index.html">이 링크</a>를 통해 다른 탭이나 창에서 열 수 있고, <a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">브라우저 개발자 도구</a>를 사용할 수도 있습니다).</p> + +<div class="hidden"> +<h6 id="Hidden_code">Hidden code</h6> + +<pre class="brush: html"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>JavaScript console</title> + <style> + * { + box-sizing: border-box; + } + + html { + background-color: #0C323D; + color: #809089; + font-family: monospace; + } + + body { + max-width: 700px; + } + + p { + margin: 0; + width: 1%; + padding: 0 1%; + font-size: 16px; + line-height: 1.5; + float: left; + } + + .input p { + margin-right: 1%; + } + + .output p { + width: 100%; + } + + .input input { + width: 96%; + float: left; + border: none; + font-size: 16px; + line-height: 1.5; + font-family: monospace; + padding: 0; + background: #0C323D; + color: #809089; + } + + div { + clear: both; + } + + </style> + </head> + <body> + + + </body> + + <script> + var geval = eval; + function createInput() { + var inputDiv = document.createElement('div'); + var inputPara = document.createElement('p'); + var inputForm = document.createElement('input'); + + inputDiv.setAttribute('class','input'); + inputPara.textContent = '>'; + inputDiv.appendChild(inputPara); + inputDiv.appendChild(inputForm); + document.body.appendChild(inputDiv); + + if(document.querySelectorAll('div').length > 1) { + inputForm.focus(); + } + + inputForm.addEventListener('change', executeCode); + } + + function executeCode(e) { + try { + var result = geval(e.target.value); + } catch(e) { + var result = 'error — ' + e.message; + } + + var outputDiv = document.createElement('div'); + var outputPara = document.createElement('p'); + + outputDiv.setAttribute('class','output'); + outputPara.textContent = 'Result: ' + result; + outputDiv.appendChild(outputPara); + document.body.appendChild(outputDiv); + + e.target.disabled = true; + e.target.parentNode.style.opacity = '0.5'; + + createInput() + } + + createInput(); + + </script> +</html></pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_code', '100%', 300, "", "", "hide-codepen-jsfiddle") }}</p> + +<h3 id="문자열_만들기">문자열 만들기</h3> + +<ol> + <li>먼저 아래의 명령어를 입력하세요. + <pre class="brush: js">var string = 'The revolution will not be televised.'; +string;</pre> + 숫자에서 했던 것과 같게, 우리는 변수를 선언하고, 문자열을 초기화 하고, 값을 반환합니다. 차이점은 오직 숫자 대신 문자열을 넣었고, 문자열 값을 따옴표로 감싸주었습니다.</li> + <li>따옴표를 빼거나 잘못쓰면 에러가 뜰 것입니다. 아래의 코드를 입력해 보세요. + <pre class="brush: js example-bad">var badString = This is a test; +var badString = 'This is a test; +var badString = This is a test';</pre> + 따옴표로 감싸져 있지 않은 텍스트는 변수 이름, 속성 이름, 예약어와 유사하다고 가정하기 때문에 이러한 코드는 작동하지 않습니다. 만약 브라우저가 찾을 수 없다면 에러가 발생할 것입니다. (e.g. "missing ; before statement"). 만약 브라우저가 문자열이 시작하는 곳은 볼 수 있지만, 끝나는 곳을 찾지 못하면 에러를 던집니다.("unterminated string literal"). 만약 당신의 프로그램이 에러를 계속 만들어낸다면, 다시 돌아가 당신의 문자열에 빠진 따옴표가 없는지 찾아보십시오.</li> + <li>다음의 코드는 당신이 변수 <code>string</code> 을 선언했다면 작동할 것입니다. 아래의 코드를 입력해보세요 : + <pre class="brush: js">var badString = string; +badString;</pre> + <code>badString</code> 은 이제 <code>string</code> 과 같은 값으로 설정되었습니다.</li> +</ol> + +<h3 id="따옴표_vs_쌍따옴표">따옴표 vs 쌍따옴표</h3> + +<ol> + <li>자바스크립트에서는 따옴표와 쌍따옴표가 모두 허용됩니다. 다음의 코드는 문제 없이 작동할 것입니다. + <pre class="brush: js">var sgl = 'Single quotes.'; +var dbl = "Double quotes"; +sgl; +dbl;</pre> + </li> + <li>따옴표와 쌍따옴표는 차이점이 거의 없어, 편한대로 사용할 수 있습니다. 하지만 당신은 문자열을 감싸는데 한 종류의 따옴표만 사용해야 되며 그렇지 않으면 에러가 발생합니다. 아래의 코드를 실행해 보세요. + <pre class="brush: js example-bad">var badQuotes = 'What on earth?";</pre> + </li> + <li>브라우저는 다른종류의 따옴표가 감싸고 있어 문자열이 아직 끝나지 않았다고 생각합니다. 예를 들어, 아래 두 가지 모두 괜찮습니다. + <pre class="brush: js">var sglDbl = 'Would you eat a "fish supper"?'; +var dblSgl = "I'm feeling blue."; +sglDbl; +dblSgl;</pre> + </li> + <li>하지만, 당신은 같은 종류의 따옴표를 문자열에 포함시킬 수 없습니다. 브라우저는 어느 따옴표가 문자열이 끝났다는 것을 알리는지 혼돈하게 됩니다. 따라서 다음의 코드는 에러가 발생합니다. + <pre class="brush: js example-bad">var bigmouth = 'I've got no right to take my place...';</pre> + 이는 우리를 다음 문단으로 이끌어 줍니다.</li> +</ol> + +<h3 id="문자열_이스케이프_문자">문자열 이스케이프 문자</h3> + +<p>직전의 문제의 코드를 해결하기 위해, 우리는 따옴표를 이스케이프 문자로 만들어야 합니다. 이스케이프 문자란 어떤 한 문자를 코드가 아닌 문자열로 만들어주는 문자입니다. 자바스크립트에서는 역슬래시 ( \ )를 문자 바로 앞에 작성함으로써 코드가 아닌 문자열로 인식하게 합니다.</p> + +<pre class="brush: js">var bigmouth = 'I\'ve got no right to take my place...'; +bigmouth;</pre> + +<p>이것은 에러가 일어나지 않습니다. 당신은 <code>\"</code> 와 같게도 사용할 수 있습니다. 자세한 사항은 <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/String#Escape_notation">이스케이프 표기법</a>을 참고하십시오</p> + +<h2 id="문자열_연결하기">문자열 연결하기</h2> + +<ol> + <li>'Concatenate'는 '결합' 을 의미하는 프로프래밍 단어입니다. 자바스크립트에서 문자열을 함꼐 결합하려면 숫자를 더할 때 사용하는 것과 동일한 더하기 (+) 연산자를 사용하지만 이 상황에서는 다른 작업을 수행합니다. 콘솔에 예를 들어 보겠습니다. + <pre class="brush: js">var one = 'Hello, '; +var two = 'how are you?'; +var joined = one + two; +joined;</pre> + 변수 <code>joined</code> 의 값은 "Hello, how are you?" 입니다.</li> + <li>마지막 예에서는, 그저 두 개의 문자열을 결합했을 뿐이지만 각 문자열 사이에 +를 포함하기만 하면 원하는 만큼의 문자열을 결합할 수 있습니다. 다음을 시도해 보십시오. + <pre class="brush: js">var multiple = one + one + one + one + two; +multiple;</pre> + </li> + <li>또한 변수와 실제 문자열을 혼합하여 사용할 수도 있습니다. 다음을 시도해 보십시오. + <pre class="brush: js">var response = one + 'I am fine — ' + two; +response;</pre> + </li> +</ol> + +<div class="note"> +<p><strong>참고</strong>: 만약 코드에 따옴표나 쌍따옴표로 묶인 문자열을 입력하면 <strong>문자열 리터럴</strong> (string literal) 이라 불립니다.</p> +</div> + +<h3 id="문자열의_연결">문자열의 연결</h3> + +<p>실제 작업에 사용되는 연결 방법에 대해 살펴보겠습니다. 이 과정에 앞부분의 예는 다음과 같습니다.</p> + +<pre class="brush: html"><button>Press me</button></pre> + +<pre class="brush: js">var button = document.querySelector('button'); + +button.onclick = function() { + var name = prompt('What is your name?'); + alert('Hello ' + name + ', nice to see you!'); +}</pre> + +<p>{{ EmbedLiveSample('Concatenation_in_context', '100%', 50, "", "", "hide-codepen-jsfiddle") }}</p> + +<p>여기서 우리는 {{domxref("Window.prompt()", "Window.prompt()")}} 를 4번째 줄에 쓰는데, 그것은 팝업 대화 상자를 통해 질문에 응답하도록 요청한 다음 지정된 변수 내에 입력하는 텍스트를 저장합니다 — 이 경우에는 <code>name</code> 에 저장합니다. 우리는{{domxref("Window.alert()", "Window.alert()")}} 을 5번째 줄에 사용하여 두 개의 문자열 리터럴 및 변수의 값이 포함된 다른 팝업을 표시합니다.</p> + +<h3 id="숫자_vs_문자열">숫자 vs 문자열</h3> + +<ol> + <li>그러면 문자열과 숫자를 추가 (또는 연결) 하면 어떻게 될까요? 콘솔에서 사용해 보겠습니다. + <pre class="brush: js">'Front ' + 242; +</pre> + 이 경우 오류가 발생할 것으로 예상할 수 있지만 잘 작동합니다. 숫자로 문자열을 나타내려는 것은 말이 안되지만 숫자를 문자열로 표현하는 것은 의미가 있습니다. 그래서 브라우저는 숫자를 문자열로 변환하고 두 문자열을 서로 연결시킵니다.</li> + <li> 숫자 두 개로도 연결할 수 있습니다 — 따옴표로 감싸면 숫자를 강제로 문자열로 만들 수 있습니다. 아래 코드를 실행해보세요(아래 코드에서 변수가 숫자인지 문자열인지를 확인하기 위해 <code>typeof</code> 연산자를 사용합니다.): + <pre class="brush: js">var myDate = '19' + '67'; +typeof myDate;</pre> + </li> + <li>만약 코드에 문자열로 바꾸고 싶은 숫자형 변수가 있지만 변수 자체의 값을 바꾸고 싶지 않거나 숫자로 바꾸고 싶은 문자열 변수가 있지만 변수 자체의 값을 바꾸고 싶지 않으면 아래와 같은 생성자를 사용할 수 있습니다: + <ul> + <li>{{jsxref("Number")}} 객체는 가능하면 어떠한 입력값이건 숫자로 바꿉니다. 다음 코드를 실행해보세요: + <pre class="brush: js">var myString = '123'; +var myNum = Number(myString); +typeof myNum;</pre> + </li> + <li>반면, 모든 숫자는 <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toString">toString()</a></code> 이라는 함수를 가지고 있습니다. 이 함수는 숫자를 동등한 문자열로 변환합니다. 다음 코드를 실행해보세요: + <pre class="brush: js">var myNum = 123; +var myString = myNum.toString(); +typeof myString;</pre> + </li> + </ul> + 이 생성자들은 어떤 상황에서는 정말 유용할 수 있습니다. 예를 들어, 만약 어떤 사용자가 숫자를 텍스트 필드 폼에 입력하면, 그 입력 값은 문자열일 것입니다. 하지만 만약 여러분이 이 숫자를 어떤 값에다 더하고 싶다면, 이 입력 값을 숫자로 변환해야 합니다. 이 경우 <code>Number()</code> 에 이 값을 넘겨줘서 이 문제를 해결할 수 있습니다.우리는 이미 <a href="https://github.com/mdn/learning-area/blob/master/javascript/introduction-to-js-1/first-splash/number-guessing-game.html#L61">Number Guessing Game, in line 61</a> 에서 이를 사용한 적이 있습니다.</li> +</ol> + +<h2 id="마치며">마치며</h2> + +<p>여기까지 자바스크립트에서 다루는 문자열의 기본이었습니다. 다음 글에서는 자바스크립트에서 문자열에 사용할 수 있는 기본 제공 메소드를 조작하는 방법에 대해 알아보겠습니다.</p> + +<p>{{PreviousMenuNext("Learn/JavaScript/First_steps/Math", "Learn/JavaScript/First_steps/Useful_string_methods", "Learn/JavaScript/First_steps")}}</p> + + + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/What_is_JavaScript">What is JavaScript?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/A_first_splash">A first splash into JavaScript</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/What_went_wrong">What went wrong? Troubleshooting JavaScript</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Variables">Storing the information you need — Variables</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Math">Basic math in JavaScript — numbers and operators</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Strings">Handling text — strings in JavaScript</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Useful_string_methods">Useful string methods</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Arrays">Arrays</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Silly_story_generator">Assessment: Silly story generator</a></li> +</ul> diff --git a/files/ko/learn/javascript/first_steps/useful_string_methods/index.html b/files/ko/learn/javascript/first_steps/useful_string_methods/index.html new file mode 100644 index 0000000000..81c18061a0 --- /dev/null +++ b/files/ko/learn/javascript/first_steps/useful_string_methods/index.html @@ -0,0 +1,461 @@ +--- +title: 문자열 제대로 다루기 +slug: Learn/JavaScript/First_steps/Useful_string_methods +translation_of: Learn/JavaScript/First_steps/Useful_string_methods +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/First_steps/Strings", "Learn/JavaScript/First_steps/Arrays", "Learn/JavaScript/First_steps")}}</div> + +<p class="summary"><span style="background-color: #fefefe; color: #000000; display: inline !important; float: none; font-family: Arial,Tahoma,Helvetica,sans-serif; font-size: 14px; font-style: normal; font-weight: normal; letter-spacing: normal; text-align: left; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;">이제까지 문자열의 기초를 살펴보았습니다. 이제부터 - 텍스트 문자열의 길이 찾기, 문자열 합치기 및 쪼개기 등과 같은- 내장된 메서드를 사용하여 문자열에서 수행할 수 있는 유용한 작업에 대해 생각해 봅시다. 문자열의 한 문자를 다른 문자로 대체하는 등의 작업을 수행합니다.</span></p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row"><span style="color: #252525; display: inline !important; float: none; font-family: Roboto,arial,sans-serif; font-size: 18px; font-style: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;">선수 과목 :</span></th> + <td> + <p><span style="color: #252525; display: inline !important; float: none; font-family: Roboto,arial,sans-serif; font-size: 18px; font-style: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;">기본 컴퓨터 활용 능력, HTML 및 CSS에 대한 기본적인 이해, JavaScript가 무엇인지 이해합니다.</span></p> + </td> + </tr> + <tr> + <th scope="row"><span style="color: #252525; display: inline !important; float: none; font-family: Roboto,arial,sans-serif; font-size: 18px; font-style: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;">목표:</span></th> + <td><span style="background-color: #fefefe; color: #000000; display: inline !important; float: none; font-family: Arial,Tahoma,Helvetica,sans-serif; font-size: 14px; font-style: normal; font-weight: normal; letter-spacing: normal; text-align: left; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;">문자열이 객체임을 이해하고, 해당 객체에서 사용할 수있는 몇 가지 기본 메서드를 사용하여 문자열을 조작하는 방법을 배웁니다.</span></td> + </tr> + </tbody> +</table> + +<h2 id="Strings_as_objects">Strings as objects</h2> + +<p id="Useful_string_methods">이전에 말했지만, 다시 말하면 - JavaScript의 모든 것이 객체입니다. 문자열을 만들 때, 예를 들면</p> + +<pre class="brush: js notranslate">var string = 'This is my string';</pre> + +<p><span style="color: #252525; display: inline !important; float: none; font-family: Roboto,arial,sans-serif; font-size: 18px; font-style: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;">변수가 문자열 객체 인스턴스되면, 결과적으로 수많은 속성과 메서드가 사용 가능하게 됩니다. <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String">String</a> 객체 페이지로 이동하여 페이지 측면의 목록을 내려다 보면 이것을 볼 수 있습니다!</span></p> + +<p><span style="color: #252525; display: inline !important; float: none; font-family: Roboto,arial,sans-serif; font-size: 18px; font-style: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-decoration-style: initial; text-indent: 0px; text-transform: none; white-space: normal;">이제 뇌가 녹기 시작하기 전에, 걱정하지 마십시오! 학습 여행 중에 초기에 대부분을 알 필요가 없습니다. 그러나 여기에서 살펴볼 몇 가지 사항을 자주 사용하게 될 것입니다.</span></p> + +<p>콘솔에 예제를 작성해 보세요. 아래의 한 가지를 제공합니다(새 탭이나 새 창에서 콘솔을 열 수 있고, 브라우저의 개발자 콘솔을 사용할 수도 있습니다).</p> + +<div class="hidden"> +<h6 id="Hidden_code">Hidden code</h6> + +<pre class="brush: html notranslate"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>JavaScript console</title> + <style> + * { + box-sizing: border-box; + } + + html { + background-color: #0C323D; + color: #809089; + font-family: monospace; + } + + body { + max-width: 700px; + } + + p { + margin: 0; + width: 1%; + padding: 0 1%; + font-size: 16px; + line-height: 1.5; + float: left; + } + + .input p { + margin-right: 1%; + } + + .output p { + width: 100%; + } + + .input input { + width: 96%; + float: left; + border: none; + font-size: 16px; + line-height: 1.5; + font-family: monospace; + padding: 0; + background: #0C323D; + color: #809089; + } + + div { + clear: both; + } + + </style> + </head> + <body> + + + </body> + + <script> + var geval = eval; + function createInput() { + var inputDiv = document.createElement('div'); + var inputPara = document.createElement('p'); + var inputForm = document.createElement('input'); + + inputDiv.setAttribute('class', 'input'); + inputPara.textContent = '>'; + inputDiv.appendChild(inputPara); + inputDiv.appendChild(inputForm); + document.body.appendChild(inputDiv); + + inputForm.addEventListener('change', executeCode); + } + + function executeCode(e) { + try { + var result = geval(e.target.value); + } catch(e) { + var result = 'error — ' + e.message; + } + + var outputDiv = document.createElement('div'); + var outputPara = document.createElement('p'); + + outputDiv.setAttribute('class','output'); + outputPara.textContent = 'Result: ' + result; + outputDiv.appendChild(outputPara); + document.body.appendChild(outputDiv); + + e.target.disabled = true; + e.target.parentNode.style.opacity = '0.5'; + + createInput() + } + + createInput(); + + </script> +</html></pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_code', '100%', 300) }}</p> + +<h3 id="문자열의_길이_찾기">문자열의 길이 찾기</h3> + +<p>간단합니다 — 간단하게 {{jsxref("String.prototype.length", "length")}} 프로퍼티를 사용할 수 있습니다. 다음 코드를 입력해 보세요.</p> + +<pre class="brush: js notranslate">var browserType = 'mozilla'; +browserType.length;</pre> + +<p>결과는 7을 리턴해야 합니다. 'mozilla'는 7글자이기 때문입니다. 이것은 여러 가지 이유로 유용합니다. 예를 들어 이름의 길이에 따라 이름의 순서를 정렬해야 하던가, 유저가 작성한 이름이 특정 길이 이상일 때 너무 길다는 것을 알려줘야 하는 경우에 사용할 수 있습니다.</p> + +<h3 id="특정_문자열_찾기">특정 문자열 찾기</h3> + +<p>관련하여, 대괄호 표기법을 이용해서 문자열 안의 문자를 구할 수 있습니다. 대괄호 표기법은 변수명 끝에 대괄호를 포함합니다. 대괄호 안에는 구하고 싶은 문자의 숫자를 포함시키면 되며, 예를 들어 아래의 경우 첫 번째 문자를 구할 수 있습니다:</p> + +<pre class="brush: js notranslate">browserType[0];</pre> + +<p>컴퓨터는 1이 아니라 0부터 숫자를 셉니다! 문자열의 마지막 문자를 구하기 위해서, 우리는 다음 코드를 사용할 수 있으며, 기술적인 <code>length</code> 프로퍼티과 같이 사용하면 아래와 같습니다:</p> + +<pre class="brush: js notranslate">browserType[browserType.length-1];</pre> + +<p>"mozilla"는 7글자이지만, 숫자는 0부터 시작하기 때문에 글자의 위치는 6입니다. 그렇기 때문에 <code>length-1</code>을 사용합니다. 예를 들어, 여러 문자열 중 첫 번째 문자를 찾아 알파벳순으로 정렬해야 할 경우에 사용할 수 있습니다.</p> + +<h3 id="문자열_내부의_하위_문자열_찾기_및_추출">문자열 내부의 하위 문자열 찾기 및 추출</h3> + +<ol> + <li>때때로 큰 문자열 안의 작은 문자열(우리는 이것을 하위 문자열이라고 이야기 한다.)을 찾고 싶을 것입니다. 이 작업은 {{jsxref("String.prototype.indexOf()", "indexOf()")}}를 사용하여 완료할 수 있습니다, which takes a single {{glossary("parameter")}} — 찾기 원하는 하위 문자열을 찾을 수 있습니다. 시도해 봅시다: + <pre class="brush: js notranslate">browserType.indexOf('zilla');</pre> + 결과는 2입니다. 하위 문자열인 "zilla"는 "mozilla'의 2번 위치(0, 1, 2— 그러므로 3번째 문자열)에서 시작합니다. 이러한 코드는 문자열을 필터링하는 데 사용될 수 있습니다. 예를 들어 웹 주소 목록에서 "mozilla"가 포함된 주소만 인쇄하고 싶은 경우입니다.</li> + <li>다른 방법으로도 할 수 있으며, 더욱 효율적일 수 있습니다. 다음 예제를 따라해 봅시다: + <pre class="brush: js notranslate">browserType.indexOf('vanilla');</pre> + 이렇게 하면 -1( 하위 문자열 (이 경우 'vanilla')이 기본 문자열에서 발견되지 않으면 반환한다.)의 결과를 얻을 수 있습니다.<br> + <br> + 하위 문자열 'mozilla'가 포함되지 않은 문자열의 모든 인스턴스를 찾으려면 이 연산자를 사용하고 아래에 표시된 것처럼 부정 연산자를 사용해서 작업을 수행할 수 있습니다. 다음과 같이 할 수 있습니다: + <pre class="brush: js notranslate">if(browserType.indexOf('mozilla') !== -1) { + // do stuff with the string +}</pre> + </li> + <li>문자열 내에서 부분 문자열이 어디에서 시작되고 어떤 문자로 끝나는지 알고 싶으면 {{jsxref("String.prototype.slice()", "slice()")}}를 사용하여 문자열을 추출할 수 있습니다. 다음을 시도해 봅시다: + <pre class="brush: js notranslate">browserType.slice(0,3);</pre> + "moz"를 반환합니다 - 첫 번째 파라메터는 추출을 시작할 문자 위치이고 두 번째 파라메터는 추출할 문자의 갯수입니다. 따라서 슬라이스는 첫 번째 위치에서부터 세 번째 위치까지 포함됩니다.</li> + <li>또한 특정 문자 뒤에 문자열의 나머지 문자를 모두 추출하려는 경우 두 번째 매개 변수를 포함하지 않고 문자열에서 나머지 문자를 추출할 위치의 문자 위치만 포함하면 됩니다. 다음을 시도해보십시오. + <pre class="brush: js notranslate">browserType.slice(2);</pre> + 이렇게 하면 "zilla"가 반환됩니다. 문자의 2번째 위치는 "z"이고 두 번째 매개 변수를 포함하지 않았기 때문에 반환된 하위 문자열은 문자열의 나머지 문자 모두입니다.</li> +</ol> + +<div class="note"> +<p><strong>Note</strong>: <code>slice()</code>의 두 번째 매개 변수는 선택사항입니다 : 이를 포함하지 않으면 <code>slice()</code>는 원래 문자열의 끝에 끝납니다. 게다가 다른 매개변수도 존재합니다.{{jsxref("String.prototype.slice()", "slice()")}} 페이지를 방문하여 더 자세하게 알 수 있습니다.</p> +</div> + +<h3 id="대소문자_변경">대/소문자 변경</h3> + +<p>문자열 메소드 {{jsxref("String.prototype.toLowerCase()", "toLowerCase()")}} 와{{jsxref("String.prototype.toUpperCase()", "toUpperCase()")}} 는 문자열을 가져와 그것을 모두 각각 대문자나 소문자로 바꿉니다. 이는 데이터베이스에 저장하기 전에 모든 사용자 입력 데이터를 표준화하려는 경우 유용합니다.</p> + +<p>다음 행을 입력하여 어떻게 되는지 살펴보겠습니다.</p> + +<pre class="brush: js notranslate">var radData = 'My NaMe Is MuD'; +radData.toLowerCase(); +radData.toUpperCase();</pre> + +<h3 id="문자열의_일부를_변경하기">문자열의 일부를 변경하기</h3> + +<p>문자열 내의 한 하위 문자열을 {{jsxref("String.prototype.replace()", "replace()")}} 를 통해 다른 하위 문자열로 바꿀 수 있습니다. 이 작업은 기본적인 수준에서 매우 간단하게 작동합니다. 하지만 아직 시도해보지 않은 고급 작업도 있습니다.</p> + +<p>그것은 2개의 매개변수를 가집니다. — 바뀜을 당하는 문자와 바꾸려는 문자입니다. 다음 예제를 따라해보세요.:</p> + +<pre class="brush: js notranslate">browserType.replace('moz','van');</pre> + +<h2 id="예제">예제</h2> + +<p>이 섹션에서는 문자열을 다루는 방법을 설명합니다. 아래의 각 실습에서는 문자열로 이루어진 배열을 루프문을 사용해 bullet list(불릿 리스트)로 표현하였습니다. 지금 배열이나 루프를 이해할 필요가 없습니다. - 이러한 내용은 추후에 설명합니다. 중요한것은 각각의 문자열이 우리가 원하는 형식으로 출력하는 코드를 작성하는 것입니다.</p> + +<p>각 예제에는 리셋 버튼이 있고, 리셋 버튼은 실수를 했거나 코드가 작동하지 않아서 재설정하는데 사용할 수 있습니다. 해결 방법을 모를 때, 해답 버튼(solution button)을 누르면 해답을 볼 수 있습니다.</p> + +<h3 id="인사말_필터링_하기">인사말 필터링 하기</h3> + +<p>첫 번째 예제는 간단히 시작해봅시다. 우리는 배열에 들어있는 크리스마스 인사말 메시지를 정렬하려고 합니다. if(...)을 사용해 각 문자열을 비교하고 크리스마스 메시지인 경우의 목록만 인쇄하려고 합니다.</p> + +<ol> + <li>먼저 각 메시지가 크리스마스 메시지인지 여부를 테스트할 수 있는 방법을 생각해봅시다. 메시지들은 어떤 문자열이 있고, 존재하는지 테스트하기 위해 어떤 방법을 사용할 수 있을까요?</li> + <li>연산자와 피연산자를 사용해 조건문을 만들어야 합니다. 연산자 왼쪽에 있는것과 연산자 오른쪽에 있는 것이 동등한가요? 또는 이 경우 왼쪽 메서드가 오른쪽으로 결과값을 전달합니까?</li> + <li>힌트 : 이 경우 메서드 호출이 결과값과 같지 않은지 테스트하는 것이 더 유용할 수 있습니다.</li> +</ol> + +<div class="hidden"> +<h6 id="Playable_code">Playable code</h6> + +<pre class="brush: html notranslate"><div class="output" style="min-height: 125px;"> + +<ul> + +</ul> + +</div> + +<textarea id="code" class="playable-code" style="height: 290px;"> +var list = document.querySelector('.output ul'); +list.innerHTML = ''; +var greetings = ['Happy Birthday!', + 'Merry Christmas my love', + 'A happy Christmas to all the family', + 'You\'re all I want for Christmas', + 'Get well soon']; + +for (var i = 0; i < greetings.length; i++) { + var input = greetings[i]; + // Your conditional test needs to go inside the parentheses + // in the line below, replacing what's currently there + if (greetings[i]) { + var result = input; + var listItem = document.createElement('li'); + listItem.textContent = result; + list.appendChild(listItem); + } +} +</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Reset"> + <input id="solution" type="button" value="Show solution"> +</div> +</pre> + +<pre class="brush: js notranslate">var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var code = textarea.value; + +function updateCode() { + eval(textarea.value); +} + +reset.addEventListener('click', function() { + textarea.value = code; + updateCode(); +}); + +solution.addEventListener('click', function() { + textarea.value = jsSolution; + updateCode(); +}); + +var jsSolution = 'var list = document.querySelector(\'.output ul\');\nlist.innerHTML = \'\';\nvar greetings = [\'Happy Birthday!\',\n \'Merry Christmas my love\',\n \'A happy Christmas to all the family\',\n \'You\\\'re all I want for Christmas\',\n \'Get well soon\'];\n\nfor(var i = 0; i < greetings.length; i++) {\n var input = greetings[i];\n if(greetings[i].indexOf(\'Christmas\') !== -1) {\n var result = input;\n var listItem = document.createElement(\'li\');\n listItem.textContent = result;\n list.appendChild(listItem);\n }\n}'; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); +</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code', '100%', 490) }}</p> + +<h3 id="대소문자_맞게_수정하기">대/소문자 맞게 수정하기</h3> + +<p>이 예제에는 영국 도시의 이름들을 모아놨습니다만 대/소문자가 잘못되어 있습니다. 우리는 이 문자들을 첫 번째 문자를 제외하고 모두 소문자로 변경해야 합니다. 이것은 다음과 같은 방식으로 할 수 있습니다:</p> + +<ol> + <li><code>input</code> 변수에 담긴 문자열 전체를 소문자로 변환한 후 새로운 변수에 저장하세요.</li> + <li>새로운 변수에 저장된 문자열의 첫 문자를 다른 변수에 저장하세요</li> + <li>Using this latest variable as a substring, replace the first letter of the lowercase string with the first letter of the lowercase string changed to upper case. Store the result of this replace procedure in another new variable.</li> + <li>Change the value of the <code>result</code> variable to equal to the final result, not the <code>input</code>.</li> +</ol> + +<div class="note"> +<p><strong>Note</strong>: A hint — the parameters of the string methods don't have to be string literals; they can also be variables, or even variables with a method being invoked on them.</p> +</div> + +<div class="hidden"> +<h6 id="Playable_code_2">Playable code 2</h6> + +<pre class="brush: html notranslate"><div class="output" style="min-height: 125px;"> + +<ul> + +</ul> + +</div> + +<textarea id="code" class="playable-code" style="height: 250px;"> +var list = document.querySelector('.output ul'); +list.innerHTML = ''; +var cities = ['lonDon', 'ManCHESTer', 'BiRmiNGHAM', 'liVERpoOL']; +for(var i = 0; i < cities.length; i++) { + var input = cities[i]; + // write your code just below here + + var result = input; + var listItem = document.createElement('li'); + listItem.textContent = result; + list.appendChild(listItem); +} +</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Reset"> + <input id="solution" type="button" value="Show solution"> +</div> +</pre> + +<pre class="brush: js notranslate">var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var code = textarea.value; + +function updateCode() { + eval(textarea.value); +} + +reset.addEventListener('click', function() { + textarea.value = code; + updateCode(); +}); + +solution.addEventListener('click', function() { + textarea.value = jsSolution; + updateCode(); +}); + +var jsSolution = 'var list = document.querySelector(\'.output ul\');\nlist.innerHTML = \'\';\nvar cities = [\'lonDon\', \'ManCHESTer\', \'BiRmiNGHAM\', \'liVERpoOL\'];\n\nfor(var i = 0; i < cities.length; i++) {\n var input = cities[i];\n var lower = input.toLowerCase();\n var firstLetter = lower.slice(0,1);\n var capitalized = lower.replace(firstLetter,firstLetter.toUpperCase());\n var result = capitalized;\n var listItem = document.createElement(\'li\');\n listItem.textContent = result;\n list.appendChild(listItem);\n\n}'; + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); +</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code_2', '100%', 450) }}</p> + +<h3 id="Making_new_strings_from_old_parts">Making new strings from old parts</h3> + +<p>In this last exercise the array contains a bunch of strings containing information about train stations in the North of England. The strings are data items that contain the three letter station code, followed by some machine-readable data, followed by a semi-colon, followed by the human-readable station name. For example:</p> + +<pre class="notranslate">MAN675847583748sjt567654;Manchester Piccadilly</pre> + +<p>We want to extract the station code and name, and put them together in a string with the following structure:</p> + +<pre class="notranslate">MAN: Manchester Piccadilly</pre> + +<p>We'd recommend doing it like this:</p> + +<ol> + <li>Extract the three-letter station code and store it in a new variable.</li> + <li>Find the character index number of the semi-colon.</li> + <li>Extract the human-readable station name using the semi-colon character index number as a reference point, and store it in a new variable.</li> + <li>Concatenate the two new variables and a string literal to make the final string.</li> + <li>Change the value of the <code>result</code> variable to equal to the final string, not the <code>input</code>.</li> +</ol> + +<div class="hidden"> +<h6 id="Playable_code_3">Playable code 3</h6> + +<pre class="brush: html notranslate"><div class="output" style="min-height: 125px;"> + +<ul> + +</ul> + +</div> + +<textarea id="code" class="playable-code" style="height: 285px;"> +var list = document.querySelector('.output ul'); +list.innerHTML = ''; +var stations = ['MAN675847583748sjt567654;Manchester Piccadilly', + 'GNF576746573fhdg4737dh4;Greenfield', + 'LIV5hg65hd737456236dch46dg4;Liverpool Lime Street', + 'SYB4f65hf75f736463;Stalybridge', + 'HUD5767ghtyfyr4536dh45dg45dg3;Huddersfield']; + +for (var i = 0; i < stations.length; i++) { + var input = stations[i]; + // write your code just below here + + var result = input; + var listItem = document.createElement('li'); + listItem.textContent = result; + list.appendChild(listItem); +} +</textarea> + +<div class="playable-buttons"> + <input id="reset" type="button" value="Reset"> + <input id="solution" type="button" value="Show solution"> +</div> +</pre> + +<pre class="brush: js notranslate">var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var solution = document.getElementById('solution'); +var code = textarea.value; + +function updateCode() { + eval(textarea.value); +} + +reset.addEventListener('click', function() { + textarea.value = code; + updateCode(); +}); + +solution.addEventListener('click', function() { + textarea.value = jsSolution; + updateCode(); +}); + +var jsSolution = 'var list = document.querySelector(\'.output ul\');\nlist.innerHTML = \'\';\nvar stations = [\'MAN675847583748sjt567654;Manchester Piccadilly\',\n \'GNF576746573fhdg4737dh4;Greenfield\',\n \'LIV5hg65hd737456236dch46dg4;Liverpool Lime Street\',\n \'SYB4f65hf75f736463;Stalybridge\',\n \'HUD5767ghtyfyr4536dh45dg45dg3;Huddersfield\'];\n\nfor(var i = 0; i < stations.length; i++) {\n var input = stations[i];\n var code = input.slice(0,3);\n var semiC = input.indexOf(\';\');\n var name = input.slice(semiC + 1);\n var final = code + \': \' + name;\n var result = final;\n var listItem = document.createElement(\'li\');\n listItem.textContent = result;\n list.appendChild(listItem);\n}'; + + +textarea.addEventListener('input', updateCode); +window.addEventListener('load', updateCode); +</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code_3', '100%', 485) }}</p> + +<h2 id="결론">결론</h2> + +<p>자바스크립트에서 문장과 단어들을 다룰 수 있는 프로그래밍 능력이 매우 중요하다. 웹사이트는 사람들과 소통하는 공간이기 때문이다. 이 문서는 문자열을 다룰 수 있는 기초적인 내용에 대해 다루었다. 이 내용은 앞으로 배우게 될 심화 과정에 도움이 될 것이다. 다음으로 배열에 대해 알아보겠다.</p> + +<p>{{PreviousMenuNext("Learn/JavaScript/First_steps/Strings", "Learn/JavaScript/First_steps/Arrays", "Learn/JavaScript/First_steps")}}</p> diff --git a/files/ko/learn/javascript/first_steps/variables/index.html b/files/ko/learn/javascript/first_steps/variables/index.html new file mode 100644 index 0000000000..7d4b2adf4e --- /dev/null +++ b/files/ko/learn/javascript/first_steps/variables/index.html @@ -0,0 +1,360 @@ +--- +title: 필요한 정보를 저장하기-변수 +slug: Learn/JavaScript/First_steps/Variables +translation_of: Learn/JavaScript/First_steps/Variables +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/First_steps/What_went_wrong", "Learn/JavaScript/First_steps/Math", "Learn/JavaScript/First_steps")}}</div> + +<p class="summary">앞선 두 수업을 듣고, 자바스크립트에 대해(웹 기술에서 어떻게 사용되는지, 큰 범위에서의 특징) 알아보았다. 이번 수업에서는 기본중에 기본인 자바스크립트의 주된 구성중 하나인 변수가 어떻게 이루어져 있는지 알아볼 것이다.</p> + +<table class="learn-box"> + <tbody> + <tr> + <th scope="row">알아야 할 것</th> + <td>기본적인 컴퓨터 지식, 기본적인 HTML, CSS, JS의 이해</td> + </tr> + <tr> + <th scope="row">목표</th> + <td>자바스크립트 변수에 대해 익혀보기</td> + </tr> + </tbody> +</table> + +<h2 id="필요한_툴">필요한 툴</h2> + +<p>이번 수업에서 컨텐츠에 대한 이해도를 테스트하고자, 코드를 입력하라는 요청을 받게 될 것이다. 만약 데스크탑 브라우저를 사용한다면, 코드를 실행하기 가장 좋은 프로그램은 브라우저의 자바스크립트 콘솔창일 것이다.(도구의 사용법에 대해 알고자 한다면 <a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">What are browser developer tools</a> 를 참고하자)</p> + +<h2 id="변수란">변수란?</h2> + +<p>변수란, 숫자(합계나 계산에 사용되는) 또는 문자열(문장의 일부로 사용되는)과 같은 값의 컨테이너입니다. 그러나 변수에 대한 한 가지 특별한 점은 포함된 값이 변경될 수 있다는 것입니다. 간단한 예를 살펴 보겠습니다:</p> + +<pre class="brush: html"><button>Press me</button></pre> + +<pre class="brush: js">const button = document.querySelector('button'); + +button.onclick = function() { + let name = prompt('What is your name?'); + alert('Hello ' + name + ', nice to see you!'); +}</pre> + +<p>{{ EmbedLiveSample('What_is_a_variable', '100%', 50, "", "", "hide-codepen-jsfiddle") }}</p> + +<p>이 예제에서 버튼을 누르면 몇 줄의 코드가 실행됩니다. 첫 번째 줄은 독자가 이름을 입력하도록 요청한 화면에 상자를 띄운 다음, 변수에 값을 저장합니다. 두 번째 줄은 변수 값에서 가져온, 이름이 포함된 환영 메시지가 표시됩니다. </p> + +<p>왜 변수가 유용한 지 이해하려면, 변수를 사용하지 않고 이 예제를 작성하는 방법에 대해 생각해 봅시다. 그러면 아마 이런 식으로 끝날 것입니다 :</p> + +<pre class="example-bad">let name = prompt('What is your name?'); + +if (name === 'Adam') { + alert('Hello Adam, nice to see you!'); +} else if (name === 'Alan') { + alert('Hello Alan, nice to see you!'); +} else if (name === 'Bella') { + alert('Hello Bella, nice to see you!'); +} else if (name === 'Bianca') { + alert('Hello Bianca, nice to see you!'); +} else if (name === 'Chris') { + alert('Hello Chris, nice to see you!'); +} + +// ... and so on ...</pre> + +<p>우리가 사용하고있는 구문을 완전히 이해하지는 못했지만, 아이디어를 얻을 수 있어야 합니다-변수를 사용할 수 없다면, 입력된 이름을 검사하는 거대한 코드 블록을 구현해야합니다. 그런 다음 해당 이름에 대한 각각의 메시지를 출력해야 합니다. 이것은 분명히 비효율적입니다 (코드는 네 가지 선택만으로도 훨씬 더 커집니다). 그리고 가능한 모든 선택 사항(모든 이름들)을 저장할 수 없어 작동하지 않을 수도 있습니다. </p> + +<p>변수는 이해하기 쉽습니다. 자바 스크립트에 대해 더 많이 배우면, 변수들은 자연스럽게 느껴질 것입니다. </p> + +<p>변수에 대한 또 다른 특별한 점은 문자열과 숫자뿐 아니라 무엇이든 포함 할 수 있다는 것입니다. 변수에는 복잡한 데이터와 놀랄만 한 기능을 수행하는 함수(Function)까지 포함될 수 있습니다. 당신은 이것에 대해 점점 더 많이 배울 것입니다. <br> + <br> + 변수는 값을 포함하고 있습니다. 이것은 중요한 차이점입니다. 변수는 값 자체가 아닙니다. 변수는 값을 위한 컨테이너입니다. 당신은 변수란 물건들을 저장할 수있는 작은 골판지 상자와 같다고 생각할 수 있습니다.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13506/boxes.png" style="display: block; height: 436px; margin: 0px auto; width: 1052px;"></p> + +<h2 id="변수의_선언">변수의 선언</h2> + +<p>변수를 사용하기 위해서, 먼저 변수를 선언해야 합니다 - 보다 정확히는, 변수를 선언한다고 부른다. 이를 위해 키워드 var를 입력하고, 당신이 원하는 변수 이름을 입력합니다.</p> + +<pre class="brush: js">var myName; +var myAge;</pre> + +<p>여기서 우리는 myName과 myAge라는 두 개의 변수를 생성합니다. 웹 브라우저의 콘솔 또는 아래 콘솔에서 두행을 입력해 보십시오 (원하는 경우, <a href="https://mdn.github.io/learning-area/javascript/introduction-to-js-1/variables/index.html">콘솔</a>을 별도의 탭이나 창에서 열 수 있음). 그 후, 자신이 명명한 변수를 만들어 보십시오.</p> + +<div class="hidden"> +<h6 id="Hidden_code">Hidden code</h6> + +<pre class="brush: html"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>JavaScript console</title> + <style> + * { + box-sizing: border-box; + } + + html { + background-color: #0C323D; + color: #809089; + font-family: monospace; + } + + body { + max-width: 700px; + } + + p { + margin: 0; + width: 1%; + padding: 0 1%; + font-size: 16px; + line-height: 1.5; + float: left; + } + + .input p { + margin-right: 1%; + } + + .output p { + width: 100%; + } + + .input input { + width: 96%; + float: left; + border: none; + font-size: 16px; + line-height: 1.5; + font-family: monospace; + padding: 0; + background: #0C323D; + color: #809089; + } + + div { + clear: both; + } + + </style> + </head> + <body> + + + </body> + + <script> + var geval = eval; + function createInput() { + var inputDiv = document.createElement('div'); + var inputPara = document.createElement('p'); + var inputForm = document.createElement('input'); + + inputDiv.setAttribute('class','input'); + inputPara.textContent = '>'; + inputDiv.appendChild(inputPara); + inputDiv.appendChild(inputForm); + document.body.appendChild(inputDiv); + + inputForm.addEventListener('change', executeCode); + } + + function executeCode(e) { + try { + var result = geval(e.target.value); + } catch(e) { + var result = 'error — ' + e.message; + } + + var outputDiv = document.createElement('div'); + var outputPara = document.createElement('p'); + + outputDiv.setAttribute('class','output'); + outputPara.textContent = 'Result: ' + result; + outputDiv.appendChild(outputPara); + document.body.appendChild(outputDiv); + + e.target.disabled = true; + e.target.parentNode.style.opacity = '0.5'; + + createInput() + } + + createInput(); + + </script> +</html></pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_code', '100%', 300) }}</p> + +<div class="note"> +<p><strong>Note</strong>: JavaScript에서는 모든 코드 명령어가 세미콜론 (;)으로 끝나야합니다. 코드를 한 줄로 작성해도 올바르게 작동할 지라도, 여러 줄의 코드를 함께 작성하는 경우에는 그렇지 않습니다. 그것을 포함시키는 습관을 갖도록 노력하십시오.</p> +</div> + +<p>변수 이름을 입력하여 변수의 값이 실행 환경에 존재하는지 테스트 할 수 있습니다.</p> + +<pre class="brush: js">myName; +myAge;</pre> + +<p>이 변수들은 값을 포함하고 있지 않은 빈 컨테이너 입니다. 변수 이름만 입력 할 경우 <code>undefined</code> 값을 반환하며 변수는 이 값(<code>undefined)</code>을 포함하게 됩니다. 만약 존재하지 않는(선언되지 않은) 변수는, 오류 메시지가 표시됩니다. 아래 변수를 입력하여 확인해 보세요.</p> + +<pre class="brush: js">scoobyDoo;</pre> + +<div class="note"> +<p><strong>Note</strong>: 존재하지만 값을 포함하고 있지 않은 변수와, 존재하지 않은 변수를 혼돈하지 마십시오. 둘은 매우 다른 것들입니다.</p> +</div> + +<h2 id="변수의_초기화">변수의 초기화</h2> + +<p>변수를 선언한 후에는 값으로 초기화 할 수 있습니다. 변수 이름 다음에 등호(<code>=</code>)와 그 뒤에 부여 할 값을 입력하여 이 작업을 수행 할 수 있습니다.</p> + +<pre class="brush: js">myName = 'Chris'; +myAge = 37;</pre> + +<p>콘솔로 돌아가 코드들을 입력해 보세요. 각각의 경우 변수에 할당한 값은 콘솔을 통해 반환되어 확인 할 수 있습니다. 또한 단순히 변수 이름을 입력하여 변수 값을 반환 할 수 있습니다. 한번 해보세요.</p> + +<pre class="brush: js">myName; +myAge;</pre> + +<p>다음과 같이 변수를 선언하고 동시에 초기화 할 수 있습니다.</p> + +<pre class="brush: js">var myName = 'Chris';</pre> + +<p>아마도 변수의 선언과 초기화를 두줄로 나누어 하는것 보다 더 빠르기 때문에 대부분 이러한 방식을 자주 사용 하게 될 겁니다.</p> + +<div class="note"> +<p><strong>Note</strong>: 여러 줄 문자열로 JavaScript 프로그램을 작성할 때(write a multiline JavaScript), 변수를 선언하기 전에 해당 변수의 값을 초기화 할 수 있습니다. 이것이 가능한 이유는 JavaScript 에서 일반적으로 변수 선언문이 다른 코드 보다 먼저 실행되기 때문인데, 이 동작을 <strong>호이스팅</strong>이라고 합니다. 자세한 내용은 <a href="/ko/docs/Web/JavaScript/Reference/Statements/var#var_호이스팅(hoisting)">var 호이스팅</a> 문서를 참고하세요.</p> +</div> + +<h2 id="변수의_재지정">변수의 재지정</h2> + +<p>변수에 값이 할당되면 다른 값을 지정하여 해당 값을 업데이트 할 수 있습니다. 콘솔에 다음 행을 입력해 보세요.</p> + +<pre class="brush: js">myName = 'Bob'; +myAge = 40;</pre> + +<h3 id="변수_이름에_대한_규칙">변수 이름에 대한 규칙</h3> + +<p>변수를 원하는 대로 이름을 부여 할 수 있지만 제한이 있습니다. 일반적으로 라틴 문자(0-9, a-z, A-Z)와 밑줄 문자를 사용해야 합니다.</p> + +<ul> + <li>오류가 발생하거나 전 세계 타인이 이해하기 어려울 수 있으므로 다른 문자를 사용하면 안됩니다.</li> + <li>변수 이름의 시작부분에 밑줄(_)을 사용하지 마세요. JavaScript 구문에서 밑줄로 시작하는 것은 특별한 의미를 가지고 있으므로 혼란을 가져올수 있습니다.</li> + <li>변수 이름의 시작부분에 숫자를 사용하지 마세요. 허용되지 않으며 오류가 발생합니다.</li> + <li>안전한 명명법은 소위 <a href="https://en.wikipedia.org/wiki/CamelCase#Variations_and_synonyms">"lower camel case"</a>(소문자 낙타 문법) 입니다. 여러 단어를 하나로 묶고 첫 단어의 시작은 소문자를 사용하며 그다음 단어의 시작은 대문자로 사용합니다. 우리는 지금까지 이 문서에서 변수 이름에 이 방법을 사용해 왔습니다.</li> + <li>포함된 데이터를 쉽게 이해 할 수 있게 변수 이름을 직관적으로 부여 합니다. 단일 문자 / 숫자 또는 긴 구절을 사용하지 마세요.변수 이름을 직관적으로 만들어, 포함된 데이터를 표현 할 수 있습니다. </li> + <li>변수는 대소문자를 구분 합니다. - <code>myage</code> 와 <code>myAge</code> 는 다른 변수 입니다.</li> + <li>마지막으로 JavaScript 예약어를 변수 이름으로 사용하면 안됩니다. (예약어란 JavaScript의 실제 구문을 구성하는 단어를 의미 합니다.) 따라서 변수 이름으로 <code>var</code>, <code>function</code>, <code>let</code>, <code>for</code> 와 같은 단어를 사용 할 수 없습니다. 브라우저는 이러한 단어를 다른 코드 아이템(예약어)로 인식하므로 오류가 발생 합니다.</li> +</ul> + +<div class="note"> +<p><strong>Note</strong>: 다음 <a href="/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#Keywords">Lexical grammar — keywords</a> 링크에서 예약어의 목록을 확인 할 수 있습니다.</p> +</div> + +<p>바람직한 변수 이름의 예:</p> + +<pre class="example-good">age +myAge +init +initialColor +finalOutputValue +audio1 +audio2</pre> + +<p>바람직하지 않은 변수 이름의 예:</p> + +<pre class="example-bad">1 +a +_12 +myage +MYAGE +var +Document +skjfndskjfnbdskjfb +thisisareallylongstupidvariablenameman</pre> + +<p>위의 지침을 염두에 두고 몇가지 변수를 추가로 작성해 보세요.</p> + +<h2 id="변수의_종류">변수의 종류</h2> + +<p>변수에 저장할 수 있는 몇가지 유형의 데이터(데이터 유형)가 있습니다. 이 섹션에서는 이를 간단히 설명하고 이후 자세히 살펴보겠습니다.</p> + +<p>지금까지 우린 두가지 형태의 데이터 유형을 살펴 봤지만 다른 유형들도 있습니다.</p> + +<h3 id="숫자">숫자</h3> + +<p>30과 같은 숫자 (정수라고도 함) 나 2.456(부동소수점 또는 부동 소수점 숫자라고도 함) 같은 십진수 숫자를 변수에 저장할 수 있습니다. JavaScript는 일부 프로그래밍 언어처럼 숫자 유형에 따른 다른 데이터 유형을 가지고 있지 않습니다. 변수에 숫자 값 대입할 때, 따옴표 사용하지 않습니다.</p> + +<pre class="brush: js">var myAge = 17;</pre> + +<h3 id="문자열">문자열</h3> + +<p>문자열은 텍스트의 조각입니다. 변수에 문자열 값을 대입할 때, 작은따옴표(')나 큰따옴표(")로 묶어야 합니다. 그렇지 않으면 JavaScript는 다른 변수 이름으로 해석하게 됩니다.</p> + +<pre class="brush: js">var dolphinGoodbye = 'So long and thanks for all the fish';</pre> + +<h3 id="불리언Booleans">불리언(Booleans)</h3> + +<p>불리언(Booleans)은 <code>true</code> 이나 <code>false</code> 라는 값을 가지는 참/거짓을 표현하는 데이터 유형입니다. 일반적으로 조건을 테스트하는 데 사용되며 그 다음 코드가 조건에 따라 실행됩니다. 예를 들어 다음과 같습니다.</p> + +<pre class="brush: js">var iAmAlive = true;</pre> + +<p>일반적으로 다음과 같은 방식으로 더 많이 사용됩니다.</p> + +<pre class="brush: js">var test = 6 < 3;</pre> + +<p>위의 코드는 "작다" 연산자(<code><</code>) 를 사용하여 6이 3보다 작은지를 확인 합니다. 예상 한대로 6이 3보다 작지 않으므로<code>false</code> 를 반환 합니다! 나중에 이러한 연산자에 대해 더 많이 배우게 됩니다.</p> + +<h3 id="배열">배열</h3> + +<p>배열은 대괄호로 묶이고 쉼표로 구분 된 여러 값을 포함하는 단일 객체입니다. 다음 코드를 콘솔에 입력해 보세요.</p> + +<pre class="brush: js">var myNameArray = ['Chris', 'Bob', 'Jim']; +var myNumberArray = [10,15,40];</pre> + +<p>이러한 배열이 정의되면 다음과 같은 구문을 사용하여 개별 값에 접근 할 수 있습니다. 다음 코드를 입력해 보세요.</p> + +<pre class="brush: js">myNameArray[0]; // should return 'Chris' +myNumberArray[2]; // should return 40</pre> + +<p>대괄호에는 반환할 값의 위치를 지정하는 인덱스 값이 들어 있습니다. 컴퓨터는 우리 사람처럼 1대신 0부터 숫자를 센다는 것을 알 수 있습니다.</p> + +<p>앞으로 배열에 대해 더 많이 배우게 됩니다.</p> + +<h3 id="객체">객체</h3> + +<p>프로그래밍에서 객체(Objects)는 실제 사물(real life object)을 모델링 하는 코드 구조입니다. 예를들어 주차장 객체는 주차장의 높이와 넓이 정보를 가지고 표현 할 수 있으며, 사람 객체는 이름, 키, 몸무게, 사용하는 언어등의 정보를 가지고 표현 할 수 있습니다.</p> + +<p>콘솔에 다음 코드를 입력해 보세요.</p> + +<pre class="brush: js">var dog = { name : 'Spot', breed : 'Dalmatian' };</pre> + +<p>객체에 저장된 정보를 검색하기 위해서는 아래 구문을 사용합니다.</p> + +<pre class="brush: js">dog.name</pre> + +<p>지금은 객체에 대해 더 자세하게 보지 않을 것입니다. - 앞으로 모듈에 있는 객체에 대해 더 많이 배울 수 있습니다.</p> + +<h2 id="지정되지_않은_타입">지정되지 않은 타입</h2> + +<p>JavaScript는 "느슨한 유형의 언어(loosely typed language)" 입니다. 즉, 다른 언어와 달리 변수에 포함 할 데이터의 유형을 지정할 필요가 없습니다.(예: 숫자? 문자열?)</p> + +<p>예를 들어, 변수를 선언하고 그 변수의 값을 따옴표로 묶은 값을 지정하면 브라우저는 변수의 값을 문자열로 인식합니다.</p> + +<pre class="brush: js">var myString = 'Hello';</pre> + +<p>따옴표 안에 숫자가 포함되어 있어도 여전히 문자열로 인식되므로 주의해야 합니다:</p> + +<pre class="brush: js">var myNumber = '500'; // oops, this is still a string +typeof(myNumber); +myNumber = 500; // much better — now this is a number +typeof(myNumber)</pre> + +<p>위의 네 줄의 코드를 하나씩 콘솔에 입력하여 결과가 무엇인지 확인해 보세요.(주석은 입력하지 마세요.) 여기에서 <code>typeof()</code> 라는 특수 함수를 사용하고 있음을 알 수 있습니다. - 이 함수는 입력한 변수의 데이터 유형을 반환합니다. 위의 코드에서 처음으로 호출될 때, <code>myNumber</code> 변수에는 <code>'500'</code> 라는 문자열이 포함되어 있으므로 <code>string</code> 을 반환해야 합니다. 두 번째는 어떤 값을 반환하는지 확인해 보세요.</p> + +<h2 id="요약">요약</h2> + +<p>지금까지 JavaScript의 변수란 무엇이며, 어떻게 생성하는지 알아보았습니다. 다음에는 JavaScript에서 숫자에 관해 자세히 살펴보고 기본 계산하는 방법을 알아보겠습니다.</p> + +<p>{{PreviousMenuNext("Learn/JavaScript/First_steps/What_went_wrong", "Learn/JavaScript/First_steps/Maths", "Learn/JavaScript/First_steps")}}</p> diff --git a/files/ko/learn/javascript/first_steps/what_is_javascript/index.html b/files/ko/learn/javascript/first_steps/what_is_javascript/index.html new file mode 100644 index 0000000000..e9198dd1d3 --- /dev/null +++ b/files/ko/learn/javascript/first_steps/what_is_javascript/index.html @@ -0,0 +1,423 @@ +--- +title: JavaScript가 뭔가요? +slug: Learn/JavaScript/First_steps/What_is_JavaScript +tags: + - Article + - Beginner + - CodingScripting + - Guide + - JavaScript + - Learn + - Script +translation_of: Learn/JavaScript/First_steps/What_is_JavaScript +--- +<div>{{LearnSidebar}}</div> + +<div>{{NextMenu("Learn/JavaScript/First_steps/A_first_splash", "Learn/JavaScript/First_steps")}}</div> + +<p class="summary">MDN의 JavaScript 초급자 과정에 오신 걸 환영합니다! 이 글은 JavaScript를 넓게 보면서 "뭔가요?", "뭘 하나요?"와 같은 질문을 답변하고, 여러분이 JavaScript에 친숙해지도록 도와드립니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">전제 조건:</th> + <td> + <p>기본적인 컴퓨터 능력, HTML과 CSS 기초.</p> + </td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>JavaScript가 뭔지, 어떤 일을 할 수 있는 지, 웹사이트에 어떻게 적용하는지 알기.</td> + </tr> + </tbody> +</table> + +<h2 id="둘러보기">둘러보기</h2> + +<p>자바스크립트는 복잡한 무언가(주기적으로 내용이 갱신되는 기능이나 능동적인 지도, 변화하는 2D/3D 그래픽, 동영상 등)를 웹페이지에 적용할 수 있게 하는 스크립트 혹은 프로그래밍 언어입입니다. 자바스크립트는 표준 웹 기술이라는 레이어 케이크에서 세번째 층이라고 볼 수 있습니다. 다른 두 층(HTML과 CSS)에 대한 보다 자세한 정보는 학습 영역의 다른 부분에서 찾아 볼 수 있습니다.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13502/cake.png" style="display: block; margin: 0 auto;"></p> + +<ul> + <li>{{glossary("HTML")}}은 제공할 웹 컨텐츠의 구조와 의미를 문단, 제목, 표, 삽입 이미지, 동영상 등으로 정의하고 부여하는 마크업 언어입니다.</li> + <li>{{glossary("CSS")}}는 배경색, 폰트 등의 레이아웃등을 지정하여 HTML 컨텐츠를 꾸며주는 스타일 규칙 언어입니다.</li> + <li>{{glossary("JavaScript")}}는 동적으로 컨텐츠를 바꾸고, 멀티미디어를 다루고, 움직이는 이미지 그리고 꽤나 많은 다른 일(물론, 전부는 아니지만 몇 줄만의 자바스크립트 코드로 얻는 결과는 놀라울겁니다.)들을 할 수 있는 스크립트 언어입니다.</li> +</ul> + +<p>3개의 요소들은 각각 유기적으로 잘 구성되어 있습니다. 예제와 같이 간단한 폼을 만들어 봅시다. HTML을 사용하여 그 구조와 목적에 맞게 마크업 할 수 있습니다: </p> + +<pre class="brush: html notranslate"><p>Player 1: Chris</p></pre> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13422/just-html.png" style="height: 28px; width: 108px;"></p> + +<p>그리고 CSS를 추가하여 이쁘게 꾸밀 수도 있습니다:</p> + +<pre class="brush: css notranslate">p { + font-family: 'helvetica neue', helvetica, sans-serif; + letter-spacing: 1px; + text-transform: uppercase; + text-align: center; + border: 2px solid rgba(0,0,200,0.6); + background: rgba(0,0,200,0.3); + color: rgba(0,0,200,0.6); + box-shadow: 1px 1px 2px rgba(0,0,200,0.4); + border-radius: 10px; + padding: 3px 10px; + display: inline-block; + cursor:pointer; +}</pre> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13424/html-and-css.png" style="height: 48px; width: 187px;"></p> + +<p>그러고 마지막으로 약간의 자바스크립트로 동적인 기능을 추가할 수 있습니다:</p> + +<pre class="brush: js notranslate">const para = document.querySelector('p'); + +para.addEventListener('click', updateName); + +function updateName() { + let name = prompt('Enter a new name'); + para.textContent = 'Player 1: ' + name; +} +</pre> + +<p>{{ EmbedLiveSample('A_high-level_definition', '100%', 80, "", "", "hide-codepen-jsfiddle") }}</p> + +<p>마지막 버전의 텍스트 라벨을 클릭하여 어떻게 되는 지 확인해봅시다. (이 데모는 Github에서도 볼 수 있습니다. <a href="https://github.com/mdn/learning-area/blob/master/javascript/introduction-to-js-1/what-is-js/javascript-label.html">source code</a> 나 <a href="http://mdn.github.io/learning-area/javascript/introduction-to-js-1/what-is-js/javascript-label.html">run it live</a>를 참고해보세요!)</p> + +<p>자바스크립트는 보다 더 많은 일들을 할 수 있습니다. 이제 더 자세한 내용을 살펴봅시다!</p> + +<h2 id="그래서_진짜_어떤_일을_할_수_있나요">그래서, 진짜 어떤 일을 할 수 있나요?</h2> + +<p>자바스크립트 언어의 핵심은 다음과 같은 일들을 할 수 있게하는 프로그래밍 기능들로 구성되어 있습니다:</p> + +<ul> + <li>변수안에 값을 저장할 수 있습니다. 위의 예시를 보면, 작성된 새로운 이름을 <code>name</code>이라는 변수에 저장하였습니다.</li> + <li>프로그밍에서 '문자열(strings)'이라고 불리는 문자들도 조작 가능합니다. 위 예시에 보면 "Player 1:"이라는 문자열을 <code>name</code>이라고 만든 변수와 겹합하여 "Player 1: Chris"라는 글을 완성할 수 있었습니다.</li> + <li>웹 페이지상의 이벤트에 응답하는 코드를 작성할 수 있습니다. 예제에서 사용한 {{Event("click")}} 이벤트를 통해 요소가 언제 클릭되고, 텍스트 라벨을 업데이트 시킬지 정정의하였습니다.</li> + <li>그리고 더 많은 것들!</li> +</ul> + +<p>하지만 더욱 흥미진진한 것은 코어 자바스크립트 언어(<em>core JavaScript</em> language) 기반의 기능성입니다. 소위 <strong>Application Programming Interfaces</strong> (<strong>APIs</strong>) 라는 것은 여러분의 자바스크립트 코드에 사용할 수 있는 추가적인 강력한 마법들을 제공합니다. </p> + +<p>API는 이미 만들어진 코드의 집합체라고 볼 수 있으며, 개발자들이 만들기 어렵고 힘든 부분을 쉽게 구현하도록 하는 프로그램이라고 볼 수 있습니다. 마치 집에서 가구를 만들 때 직접 디자인하고, 재료를 구하고, 재단하고, 못을 박고 하는 등 혼자서 모든 것을 하는 대신 가구 만들기 키트를 사는 것과 같다고 보면 됩니다.</p> + +<p>일반적으로 두 종류로 구분됩니다.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13508/browser.png" style="display: block; height: 511px; margin: 0px auto; width: 815px;"></p> + +<p><strong>Browser API</strong>는 웹 브라우저에 설치된 API들로, 컴퓨터 환경구성으로 부터 데이터를 보이게 하고 복잡한 일들을 하게 합니다. 예를 들어:</p> + +<ul> + <li><a href="https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model">DOM (Document Object Model) API</a> 는 동적으로 페이지의 스타일을 정하는 등 HTML과 CSS를 알맞게 조정하는 역할을 합니다. 우리가 매일 보는 팝업창이나, 위의 사진과 같이 컨텐츠들이 보여지는 것들이 모두 DOM의 결과라고 볼 수 있습니다.</li> + <li><a href="https://developer.mozilla.org/en-US/docs/Web/API/Geolocation">Geolocation API</a>은 지리적인 정보를 검색하게 해줍니다. 이는 <a href="https://www.google.com/maps">Google Maps</a>이 어떻게 위치를 찾고 지도에 표시하는지 알 수 있게 합니다.</li> + <li><a href="https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API">Canvas</a> 와 <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API">WebGL</a> API는 2D와 3D 그래픽을 만들 수 있도록 합니다. 이러한 웹 기술을 사용하여 다양하고 재미있는 것들을 지원합니다. —<a href="https://www.chromeexperiments.com/webgl">Chrome Experiments</a> 와 <a href="http://webglsamples.org/">webglsamples</a>을 참조해보세요.</li> + <li>HTMLMediaElement 와 <a href="/en-US/docs/Web/API/WebRTC_API">WebRTC</a> 같은 <a href="https://developer.mozilla.org/en-US/Apps/Fundamentals/Audio_and_video_delivery">Audio and Video API</a>는 음악과 비디오를 웹 페이지 상에서 재생하고, 웹캠으로 캡처하고 다른 컴퓨터에 표시하는 등의 멀티미디어를 활용할 수 있는 재미있는 기술을 지원합니다. (<a href="http://chrisdavidmills.github.io/snapshot/">Snapshot demo</a>를 한번 참조해보세요.)</li> +</ul> + +<div class="note"> +<p><strong>Note</strong>: 대부분의 데모 코드들은 오래된 브라우저에서는 실행이 안될 수 있으니, FireFox, Chrome, Edge, Opera와 같은 최신의 브라우저를 사용하는 것을 추천합니다. 실제 배포가 되는 코드처럼 여러 사용자가 사용할 수 있음을 고려하여 <a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing">cross browser testing</a>(여러 브라우저를 이용하여 테스트)를 해보는 것이 좋습니다.</p> +</div> + +<p><strong>Third party API</strong> 는 브라우저에 기본적으로 설치된 API가 아닌 인터넷에서 개인적으로 정보와 코드를 얻어 프로그래밍한 것을 말합니다. 예를 들어:</p> + +<ul> + <li><a href="https://dev.twitter.com/overview/documentation">Twitter API</a>는 웹사이트에 가장 최근의 트윗을 보여주도록 합니다.</li> + <li><a href="https://developers.google.com/maps/">Google Maps API</a>와 <a href="https://wiki.openstreetmap.org/wiki/API">OpenStreetMap API</a>는 웹사이트에 원하는 지도를 넣어주고 추가기능을 지원합니다.</li> +</ul> + +<div class="note"> +<p><strong>Note</strong>: 이러한 API 들은 고급 과정이며, 이 과정에서는 다루지 않을 것입니다. 이 API들에 대한 보다 자세한 정보는 <a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Client-side_web_APIs">Client-side web APIs module</a>에서 살펴보세요.</p> +</div> + +<p>물론 이것말고도 엄청나게 다양한 API들이 존재합니다! 하지만, 이 수업을 듣고 Facebook, Google Maps, Instagram등을 만들 수는 없으니 흥분하지는 말길 바랍니다. 이것보다 우리는 먼저 기본적인 것에 대해 배울 것이고 이것이 곧 이 수업을 진행하는 목적입니다. 자 시작해봅시다!</p> + +<h2 id="웹_페이지에서_JavaScript는_어떤_일을_하나요">웹 페이지에서 JavaScript는 어떤 일을 하나요?</h2> + +<p>여기서 몇가지 코드를 실제로 살펴보고, 페이지에서 자바스크립트가 언제 어떻게 작동하는지 알아 볼 것입니다.</p> + +<p>브라우저에서 웹페이지를 불러올 때 어떤 일이 발생하는지 생각해봅시다(먼저 <a href="/en-US/Learn/CSS/Introduction_to_CSS/How_CSS_works#How_does_CSS_actually_work">How CSS works</a>를 읽어 보세요.). 브라우저에서 웹페이지를 불러올 때, 실행 환경(브라우저 탭)안에서 HTML, CSS, Javascript 코드가 실행됩니다. 이는 마치 공장에서 원재료(코드)가 일련의 과정을 거쳐 제품(웹페이지)으로 탄생되는 것과 같습니다.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13504/execution.png" style="display: block; margin: 0 auto;"></p> + +<p>자바스크립트는 HTML과 CSS가 결합되고 웹페이지 상에서 올려진 후, 브라우저의 자바스크립트 엔진에 의해 실행됩니다. 이는 페이지의 구조와 스타일등을 정해놓고, 자바스크립트가 실행된다는 것과 같은 의미입니다.</p> + +<p>동적으로 사용자 인터페이스를 업데이트하는 자바스크립트의 사용은 Document Object Model API를 통해 HTML과 CSS를 수정하는 것으로 좋은 현상입니다. 만약 자바 스크립트가 HTML과 CSS 전에 실행되었다면 문제가 분명 발생할 것입니다.</p> + +<h3 id="브라우저_보안성">브라우저 보안성</h3> + +<p>각각의 브라우저 탭들은 코드가 실행되는 개별적인 구성(이러한 것은 "실행 환경"이라고 지칭한다)입니다. 이는 각 탭의 대부분의 경우는 완전히 독립적이고, 하나의 탭의 코드는 다른 탭이나 웹사이트에 직접적으로 영향을 줄 수 없다는 의미입니다 . 이는 보안성에 좋은 방법입니다. 만약 이러한 부분이 없다면, 해커들이 다른 웹사이트로 부터 정보를 가로채는 등 악랄한 짓들을 할 수 있습니다.</p> + +<div class="note"> +<p><strong>Note</strong>: 물론 코드나 정보를 동떨어진 웹사이트나 탭으로 전송할 수 있는 안전한 방식이 존재합니다. 하지만 지금 과정과는 거리가 멀기 때문에 여기서는 다루지 않도록 하겠습니다.</p> +</div> + +<h3 id="자바스크립트_실행_순서">자바스크립트 실행 순서</h3> + +<p>브라우저에서 자바스크립트를 만났을 때 일반적으로는 위에서 아래 순서대로 실행됩니다. 이는 순서에 주의해서 코드를 작성해야한다는 의미입니다. 예를 들어, 아래의 첫번째 예재를 통해 자바스크립트 블록을 반환해봅시다:</p> + +<pre class="brush: js notranslate">const para = document.querySelector('p'); +//HTML 요소 중 p태그를 선택 + +para.addEventListener('click', updateName); +//para에 저장된 객체가 클릭되었을 때 updateName 함수를 실행 + +function updateName() { + let name = prompt('Enter a new name'); + //'Enter a new name'과 입력란 출력하여 입력받은 값을 name에 저장 + para.textContent = 'Player 1: ' + name; + //papa(p태그)에 새로운 문자열 저장 +}</pre> + +<p>먼저 p태그의 요소를 para변수에 저장합니다(1번줄). 그리고 event listener를 붙여(3번줄) p태그가 클릭되었을 때 <code>updateName()</code>코드 블록(중괄호로 묶여있는 부분)이 (5-8번줄) 실행되도록 합니다. <code>updateName()</code> 코드 블록(이렇게 계속적으로 사용할 수 있는 코드 블럭을 함수라고 합니다.). 사용자로 하여금 새로운 이름을 입력받기를 요청하고, 사용자가 이름을 입력하면 화면에 출력하게 됩니다.</p> + +<p>만약 1번줄과 3번줄을 바꿨다면 코드는 실행되지 않을 것입니다. 대신 브라우저의 개발자 콘솔창에 다음과 같은 에러 알림이 뜰 것입니다. — <code>TypeError: para is undefined</code>. 이는 para라는 객체가 아직 존재하지 않는다는 뜻으로, para라는 변수에 event listener는 추가할 수 없습니다</p> + +<div class="note"> +<p><strong>Note</strong>: 이는 매우 일반적인 에러이기 때문에, 프로그램을 실행할 때 코드 상에서 사용되는 객체에 대해 주의할 필요가 있습니다.</p> +</div> + +<h3 id="해석형_언어와_컴파일러형_언어">해석형 언어와 컴파일러형 언어</h3> + +<p>프로그래밍을 하는 입장에서 인터프리트와 컴파일이라는 개념에 대해서는 들어보았을 것입니다. 자바스크립트는 해석형 언어입니다. 따라서 코드가 위에서 아래로 순차적으로 실행되고 그 즉시 결과가 반환됩니다. 브라우저에서 동작하기 전에 다른 방식으로 코드를 변환할 필요가 없습니다.</p> + +<p>반면에 컴파일러형 언어는 컴퓨터에 의해 동작되기전 다른 형식으로 변환하는 언어입니다. 예를 들면 C/C++과 같은 언어는 어셈블리어로 컴파일되어 동작됩니다.</p> + +<p>이 둘의 관점은 각각의 장점을 가지고 있으니 다음장 부터 한번 알아봅시다.</p> + +<h3 id="서버측_코드와_클라이언트측_코드">서버측 코드와 클라이언트측 코드</h3> + +<p>웹 개발 맥락에서 서버측과 클라이언트측 코드에 대해 들어보았을 것입니다. 클라이언트측 코드란 사용자의 컴퓨터에서 작동되는 코드입니다. 만약 웹페이지를 보고자 한다면, 클라이언트측 코드가 사용자의 컴퓨터로 다운로드되고 브라우저가 이를 표시합니다. 이러한 자바스크립트 모듈을 정확히는 클라이언트측 자바스크립트라고 합니다.</p> + +<p>반면 서버측 코드는 서버에서 작동되고, 그 결과가 사용자의 브라우저에 넘어가 표시됩니다. PHP, Python, Ruby, ASP.NET등이 서버측 웹 언어의 대표적 예라고 볼 수 있습니다. 물론 자바스크립트도 가능합니다! 유명한 Node.js란 환경을 통해 서버측에서도 자바스크립트가 사용 가능합니다. <a href="/en-US/docs/Learn/Server-side">Dynamic Websites – Server-side programming</a>에서 서버측 자바스크립트에 대해 더 알 수 있습니다.</p> + +<h3 id="동적_VS_정적_코드">동적 VS 정적 코드</h3> + +<p>"동적"이라는 말은 클라이언트측 서버측 언어 모두를 가르킵니다. 이는 각기 다른 상황에서 적절한 정보가 보이고, 컨텐츠를 웹페이지나 앱 상에 계속적으로 노출시키는 역할을 합니다. 서버측 코드는 데이터베이스로 부터 데이터를 던지는 등 동적으로 새로운 컨텐츠들을 만듭니다. 반면에, 클라이언트측 자바스크립트는 새로운 HTML 표를 만들어 서버에서 요청한 데이터를 뿌려 사용자에게 보이는 등 동적으로 브라우저 안에서 작동됩니다. 이 둘 사이는 서로 미묘한 차이가 있지만, 서로 연관되어 있고 서버측 클라이언트측의 관계와 접근에 대해 알 필요가 있습니다.</p> + +<p>동적으로 바뀌지 않는 페이지를 "정적"페이지라고 합니다. (항상 같은 콘텐츠를 보여줍니다.)</p> + +<h2 id="웹_페이지에_JavaScript를_어떻게_넣나요">웹 페이지에 JavaScript를 어떻게 넣나요?</h2> + +<p>자바스크립트는 CSS와 같은 방식으로 HTML 페이지에 적용됩니다. CSS는 외부의 스타일시트를 적용하기 위해 link 요소를 사용하거나 내부의 스타일시트를 적용하기 위해 style 요소를 사용하는 반면,자바스크립트는 HTML상에서 오직 script 태크만으로 사용이 가능합니다. 어떻게 작동되는지 한번 살펴봅시다.</p> + +<h3 id="HTML_내부의_자바스크립트">HTML 내부의 자바스크립트</h3> + +<ol> + <li>먼저, 예제로 주어진 <a href="https://github.com/mdn/learning-area/blob/master/javascript/introduction-to-js-1/what-is-js/apply-javascript.html">apply-javascript.html</a>파일을 저장합니다.</li> + <li>파일을 브라우저와 편집기 상에서 둘다 엽니다. HTML으로 만든 클릭 버튼이 있는 간단한 웹페이지를 볼 수 있습니다.</li> + <li>그런다음, 편집기로 가서 <code></body></code> 태그 직전에 다음의 코드를 추가하도록 합니다: + <pre class="brush: html notranslate"><script> + + // JavaScript goes here + +</script></pre> + </li> +</ol> + +<p>그러고 아래의 자바스크립트 코드를 <script></script>사이에 넣음으로서 페이지 상에서 동작이 가능하게끔 할 수 있습니다.( 위 코드에서 "// JavaScript goes here" 부분에 아래의 코드를 추가하면 됩니다.)</p> + +<pre class="brush: js notranslate" dir="rtl"><code>document.addEventListener("DOMContentLoaded", function() { + function createParagraph() { + let para = document.createElement('p'); + para.textContent = 'You clicked the button!'; + document.body.appendChild(para); + }</code> + + const buttons = document.querySelectorAll('button'); + + for(let i = 0; i < buttons.length ; i++) { + buttons[i].addEventListener('click', createParagraph); + } +});</pre> + +<ol> + <li>파일을 저장하고 새로고침을 눌러보세요. 이제 버튼을 클릭하면 새로운 문단이 아래쪽에 생기는 것을 볼 수 있습니다.</li> +</ol> + +<div class="blockIndicator note"> +<p>각각의 문법에 대해서는 이후 더 자세히 다루기 때문에, 동작여부만 확인하고 넘어가도 무방합니다.</p> +</div> + +<div class="note"> +<p><strong>Note</strong>: 만약 예제가 실행되지 않는다면, 돌아가서 올바른지 한 번 더 체크해보도록 하세요. 혹시 저장할 때 확장자를 .html 로 하지 않았나요? 혹시 {{htmlelement("script")}} 를<code></body></code> 태그 뒤에 붙인 건 아닌가요? 다음과 같이 자바스크립트를 작성했나요? <strong>자바스크립트는 까다로운 언어이기 때문에 정확하게 문법을 지킬 필요가 있습니다. 그렇지 않으면 제대로 동작하지 않을 수 도 있습니다.</strong></p> +</div> + +<div class="note"> +<p><strong>Note</strong>: 깃허브에서도 이 코드를 볼 수 있습니다. <a href="https://github.com/mdn/learning-area/blob/master/javascript/introduction-to-js-1/what-is-js/apply-javascript-internal.html">apply-javascript-internal.html</a> (<a href="http://mdn.github.io/learning-area/javascript/introduction-to-js-1/what-is-js/apply-javascript-internal.html">see it live too</a>).</p> +</div> + +<h3 id="외부의_자바스크립트">외부의 자바스크립트</h3> + +<p>만약에 외부 파일로 자바스크립트를 위치시키고 싶다면 어떻게 할까요? 이에 대해서 알아봅니다.</p> + +<ol> + <li>먼저, HTML 파일이 있는 디렉토리에 <code>script.js</code>라는 새로운 파일을 만듭니다. 파일의 확장자가 .js이면 그 파일이 자바스크립트로 이루어져 있음을 뜻합니다.</li> + <li>아래의 태그를 HTML 코드에 복사 후 저장합니다.</li> + <li> + <pre class="syntaxbox notranslate"><script src="script.js"></script></pre> + </li> + <li>script.js 의 내용을 다음과 같이 바꿉니다. + <pre class="notranslate"><code>function createParagraph() { + let para = document.createElement('p'); + para.textContent = 'You clicked the button!'; + document.body.appendChild(para); +} + +const buttons = document.querySelectorAll('button'); + +for(let i = 0; i < buttons.length ; i++) { + buttons[i].addEventListener('click', createParagraph); +}</code></pre> + </li> + <li>저장하고 브라우저를 새로고침하면 앞과 똑같은 결과가 나올것입니다. 똑같이 작동하기 때문에 이제 자바스크립트는 외부에서 만들 수 있음을 알 수 있습니다. 이는 코드를 만들고 구성하는 입장에서 좋으며, 여러 HTML파일로 부터 재사용이 가능합니다. 더군다나 HTML은 스크립트의 본문이 외부로 분리되어 간결해집니다.</li> +</ol> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: 깃허브에서 이 버전을 볼 수 있습니다. <a href="https://github.com/mdn/learning-area/blob/master/javascript/introduction-to-js-1/what-is-js/apply-javascript-external.html">apply-javascript-external.html</a> 그리고 <a href="https://github.com/mdn/learning-area/blob/master/javascript/introduction-to-js-1/what-is-js/script.js">script.js</a> (<a href="http://mdn.github.io/learning-area/javascript/introduction-to-js-1/what-is-js/apply-javascript-external.html">see it live too</a>).</p> +</div> + +<h3 id="인라인_JavaScript_처리기">인라인 JavaScript 처리기</h3> + +<p>실제 HTML 속에 포함된 자바스크립트코드를 함께 쓸 수 있습니다. 이는 다음과 같으니 참고해보세요:</p> + +<pre class="brush: js example-bad notranslate">function createParagraph() { + let para = document.createElement('p'); + para.textContent = 'You clicked the button!'; + document.body.appendChild(para); +} +//HTML 내의 <scirpt>태그 내부에 작성 +</pre> + +<pre class="brush: html example-bad notranslate"><button onclick="createParagraph()">Click me!</button></pre> + +<p>이는 다음과 같은 예제로 볼 수 있습니다.</p> + +<p>이 데모 예제는 <button>태그에 onclick속성에 대한 값을 함수이름으로 넣어 버튼이 클릭될 때마다 함수가 실행되도록 작성하였습니다.</p> + +<p><strong>하지만, 이 방법은 효율적이지 않습니다. </strong>이는 자바스크립트와 함께 HTML 소스를 복잡하게 할 수 있습니다. 또한 함수를 만들기 위한 모든 버튼 마다 <code>onclick="createParagraph()"</code> 속성을 포함해야합니다.</p> + +<p>JavaScript 코드만으로도 모든 버튼에 함수를 연결할 수 있습니다. 위의 내용을 의도한대로 수정한다면 다음과 같습니다:</p> + +<pre class="notranslate">const buttons = document.querySelectorAll('button'); +//모든 <button>태그를 List 형태로 buttons 변수에 저장한다. + +for (let i = 0; i < buttons.length ; i++) { + buttons[i].addEventListener('click', createParagraph); +} +//복수이기 때문에 for를 사용해 루프를 돌린다. +</pre> + +<p>이 코드는 onclick 속성 코드 보다 조금 길어보이지만, 페이지가 많든, 버튼의 수가 많든 적든 상관없이 모든 버튼들이 같은 기능을 할 수 있도록 합니다. 물론 자바스크립트 코드를 변경할 필요가 없습니다.</p> + +<div class="note"> +<p><strong>Note</strong>: <code>apply-javascript.html 수정을 해보고 버튼을 한 번 추가해 보세요.</code> 실행해보면 버튼 하나하나 클릭할 때 마다 글이 보일 것입니다. 꽤 깔끔하지 않은가요?</p> +</div> + +<h3 id="스크립트의_로딩_방법">스크립트의 로딩 방법</h3> + +<p> 작성된 스크립트를 브라우저가 적절한 때에 로딩하는것에 대해 몇가지 이슈가 있습니다. 중요한 것은 모든 HTML 요소는 순서대로 페이지에 로드된다는 것입니다. 만약 당신이 자바스크립트를 이용해 HTML 요소를 조작할 경우(정확하게는 DOM), 자바스크립트 코드가 조작 대상인 HTML 요소보다 먼저 실행된다면 조작할 요소가 존재하지 않는 상태이기 때문에 제대로 동작하지 않을 것입니다.</p> + +<p>위의 코드 예제에서, 내부와 외부의 자바스크립트는 HTML Document의 <code>body</code>가 해석되기 전인 <code>head </code>부분에 로드되고 실행되었습니다. 이는 에러를 일으킬 수 있습니다. 그래서 여기에 사용되는 몇가지 해결방법들이 있습니다.</p> + +<p><strong>내부 자바스크립트 예제</strong>에서는 다음과 같이 구성하면 됩니다:</p> + +<pre class="notranslate"><code>document.addEventListener("DOMContentLoaded", function() { + ... +});</code></pre> + +<p>이 이벤트리스너는 <code>"DOMContentLoad" </code>이벤트가 발생되었을 때<code> function()</code>을 실행한다는 의미입니다. (<a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events">이벤트 리스너</a>에 관해서는 이번 코스에서 다루게 됩니다.) <code>"DOMContentLoad"</code> 이벤트는 브라우저가 완전히 로드되고 해석될때 발생됩니다. <code>function(){}</code> 내부의 자바스크립트 구문은 이벤트가 발생되기 전까지는 실행되지 않습니다. 따라서 모든 <code>body</code>태그의 요소가 로드된 이후 자바스크립트 코드가 실행되도록 만들어 에러를 피할 수 있습니다.</p> + +<p><strong>외부 자바스크립트</strong> 예제에서는 좀더 최신의 자바스크립트 문법인 <code>async </code>속성을 사용하게 됩니다. 일반적으로 <code>HTML</code>요소를 로딩하는 중 <code><scirpt></code>태그를 만나면 JavaScript의 내용이 모두 다운될 때까지 <code>HTML</code>로딩은 멈추게 되는데, <code>async</code>요소는 비동기방식으로 <code><script></code>태그에 도달했을 때 브라우저에게 <code>HTML </code>요소를 멈추지 않고 다운받도록 유지시킵니다.</p> + +<pre class="notranslate"><code><script src="script.js" async></script></code></pre> + +<p>이 경우 <code>script</code>와 <code>HTML</code>은 모두 동시에 로드되고 작동할 것입니다.</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: 외부 스크립트 경우 async 속성을 사용하면 되기 때문에 내부 스크립트처럼 DOMContentLoaded이벤트를 사용할 필요가 없습니다. 하지만 async속성은 외부 스크립트의 경우만 동작합니다.</p> +</div> + +<p>예전 방식은 <code>scirpt </code>요소를 <code>body</code>태그의 맨 끝에 넣는 방법이었습니다(<code></body></code> 바로 위에). 이 방식을 사용해도 <code>body</code>태그가 모두 로드된 이후 <code>scirpt</code>가 실행되게 만들 수 있습니다. 문제는 이 방법과 <code>DOMContentLoaded</code>를 이용한 방법 모두<code> HTML DOM</code>이 로드되기 전까지 <code>script</code>의 로딩과 파싱이 완전히 차단된다는 것입다. 이는 많은 자바스크립트 코드를 다루는 규모가 큰 사이트의 경우 사이트를 느리게 만드는 중요한 성능 문제를 야기할 수 있습니다. 이것이 <code>async </code>속성을 사용해야 하는 이유입니다!</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: 자바스크립트의 비동기 개념은 이해하는데 시간이 오래 걸리기 때문에, 지금 이해되지 않는다면 현재 단계에선 외부 스크립트 방식만 사용하고 넘어가도 무방합니다.</p> +</div> + +<h4 id="async_defer">async & defer</h4> + +<p>더 깊게 들어가보면 이러한 코드문제를 해결하기 위한 방법은 실제로 두가지가 있습니다. — <code>async</code> 와<code>defer</code> 입니다. 두 가지의 차이를 봅시다.</p> + +<p>async 스크립트는 페이지 렌더링의 중단 없이 스크립트를 다운로드 하고, 또한 스크립트의 다운로드가 끝나자 마자 이를 실행시킵니다. async는 외부 스크립트끼리의 구체적인 실행 순서는 보장하지 않고, 단지 나머지 페이지가 나타나는 동안 스크립트가 비동기방식으로 다운로드 되어 중단되지 않는다는 것만 보장합니다. async는 각각의 스크립트가 독립적으로, 서로에게 의존하지 않는 관계일 때 적절합니다.</p> + +<p>아래의 예제를 보시죠:</p> + +<pre class="notranslate"><code><script async src="js/vendor/jquery.js"></script> + +<script async src="js/script2.js"></script> + +<script async src="js/script3.js"></script></code></pre> + +<p>3개의 스크립트를 로딩하지만 이들의 순서는 보장할 수 없습니다. 이는 <code>script2.js</code>나 <code>script3.js</code>에 있는 함수가<code> jquery.js</code>의 함수를 사용한다면 에러를 발생될 수 있다는 것을 의미합니다.</p> + +<p>Defer는 이와 다르게 순서대로 다운로드 한 후 모든 스크립트와 내용이 다운로드 되었을 때 실행됩니다:</p> + +<pre class="notranslate"><code><script defer src="js/vendor/jquery.js"></script> + +<script defer src="js/script2.js"></script> + +<script defer src="js/script3.js"></script></code></pre> + +<p>따라서 위의 예제의 경우에는 <code>jquery.js</code> -> <code>script2.js</code> -> <code>script3.js</code> 의 순서가 보장됩니다.</p> + +<p>요약 :</p> + +<ul> + <li>만약 scirpt들이 각각의 스크립트에 의존하지 않고 독립적으로 파싱되도 상관없다면, <code>async</code> 를 사용합니다.</li> + <li>먄약 sciprt들이 의존하고 하나의 스크립트가 파싱될때까지 기다려야 한다면, <code>defer</code> 를 사용하고 각각의 <code><script></code> 태그들을 실행되길 원하는 순서대로 작성합니다.</li> +</ul> + +<h2 id="주석">주석</h2> + +<p>HTML과 CSS와 같이, 자바스크립트에서도 주석문의 사용이 가능합니다. 주석문은 브라우저 실행때는 무시되어 넘어가고 다른 개발자로 하여금 어떻게 구성되고 작동되는지 설명해주는 역할을 합니다(물론 자신의 훗날 코드를 다시 보았을 때 빨리 기억하고, 이해할 수 있게끔 도와주기도 합니다.). 주석문은 매우 유용하고 코딩시 자주 사용됩니다(특히 큰 프로젝트에서). 주석문에는 두가지 종류가 있습니다:</p> + +<ul> + <li>두개의 슬래시(//)를 통해 한 줄의 주석이 가능합니다. + <pre class="brush: js notranslate">// I am a comment</pre> + </li> + <li> /* 와 */를 사용하여 그 사이에 여러 줄의 주석문의 구성이 가능합니다. + <pre class="brush: js notranslate">/* + I am also + a comment +*/</pre> + </li> +</ul> + +<p>예를 들자면, 앞의 데모예제에 주석문을 다음과 같이 달 수 있습니다.</p> + +<pre class="brush: js notranslate">// Function: creates a new paragraph and append it to the bottom of the HTML body. + +function createParagraph() { + let para = document.createElement('p'); + para.textContent = 'You clicked the button!'; + document.body.appendChild(para); +} + +/* + 1. Get references to all the buttons on the page and sort them in an array. + 2. Loop through all the buttons and add a click event listener to each one. + + When any button is pressed, the createParagraph() function will be run. +*/ + +const buttons = document.querySelectorAll('button'); + +for (let i = 0; i < buttons.length ; i++) { + buttons[i].addEventListener('click', createParagraph); +}</pre> + +<h2 id="정리">정리</h2> + +<p>지금까지 우리는 자바스크립트의 첫걸음을 떼었습니다. 여기서 자바스크립트를 왜 사용하고 어떻게 사용하는지에 대한 방법들에 대한 기초적인 부분을 배웠습니다. 여러 예제 코드를 봄으로써, 웹사이트와 다른 곳에서의 코드상 자바스크립트가 어떻게 구성되어있는지 배웠습니다.</p> + +<p>자바스크립트가 지금은 조금 어려울 수 있으나, 걱정하지 마세요. 이 수업은 첫 단계인만큼 앞으로 더 많은 것을 배우기 위해 감각을 키우기 위한 수업입니다. 다음 수업에서 우리는 <a href="/en-US/docs/Learn/JavaScript/Introduction_to_JavaScript_1/A_first_splash">plunge straight into the practical</a>를 통해 앞으로 더 나아가고 스스로 자바스크립트 예제를 실행해볼 것입니다.</p> diff --git a/files/ko/learn/javascript/first_steps/what_went_wrong/index.html b/files/ko/learn/javascript/first_steps/what_went_wrong/index.html new file mode 100644 index 0000000000..44030c4057 --- /dev/null +++ b/files/ko/learn/javascript/first_steps/what_went_wrong/index.html @@ -0,0 +1,237 @@ +--- +title: 자바스크립트 문제해결 +slug: Learn/JavaScript/First_steps/What_went_wrong +translation_of: Learn/JavaScript/First_steps/What_went_wrong +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/First_steps/A_first_splash", "Learn/JavaScript/First_steps/Variables", "Learn/JavaScript/First_steps")}}</div> + +<p class="summary">이전 수업에서 "숫자맞추기" 프로그램을 만들어봤을때, 프로그램이 돌아가지 않는다는 것을 볼 것이다. 하지만 여기서 자바스크립트의 에러를 찾고 고치는 방법에 대해 알려주니 겁먹지 말고 도전해보자!</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">알아야 할 것</th> + <td>기본적인 컴퓨터 이해. HTML, CSS, 자바스크립트의 이해</td> + </tr> + <tr> + <th scope="row">목표</th> + <td>코드상의 문제를 고치는 능력과 자신감 고취</td> + </tr> + </tbody> +</table> + +<h2 id="에러의_종류">에러의 종류</h2> + +<p>일반적으로, 코드가 잘못된 이유에는 2가지 종류가 있으니 살펴보자.</p> + +<ul> + <li><strong>구문 에러(Syntax errors)</strong>: 코드 상의 구문 에러로 대개 철자가 잘못되어 작동이 안되거나 중간에 프로그램이 중지된다. 물론 여기서 에러 메시지가 출력되므로 확인할 수 있다. 코드 편집기 툴을 사용하고 에러 메시지의 의미만 파악할 수 있다면, 충분히 고칠 수 있다.</li> + <li><strong>논리 에러(Logic errors)</strong>: 구문은 올바르지만, 코드의 의미자체가 잘못된 경우이다. 즉 프로그램은 정상적으로 돌아가지만, 원하는 결과를 얻지 못하는 경우이다. 에러 메시지가 직접적으로 표시되지 않기 때문에, 일반적으로 구문에러보다 에러 수정이 힘들다.</li> +</ul> + +<p>물론, 간단하지는 않지만 좀 더 세분화된 분류가 있다. 그렇지만, 위의 분류가 처음에는 이해하기 좋다. 우리는 앞으로 이 두가지 종류에 대해 알아볼 것이다.</p> + +<h2 id="잘못된_예">잘못된 예</h2> + +<p>시작하기 앞서, 이전에 볼 '숫자맞추기'게임을 살펴보자 (이번 시간을 제외하고는 앞으로 일부러 에러를 만든 코드를 볼 것입니다.) 깃허브에 가서 로컬 지역에 저장합니다. -> <a href="https://github.com/mdn/learning-area/blob/master/javascript/introduction-to-js-1/troubleshooting/number-game-errors.html">number-game-errors.html</a> (see it <a href="http://mdn.github.io/learning-area/javascript/introduction-to-js-1/troubleshooting/number-game-errors.html">running live here</a>).</p> + +<ol> + <li>시작하기에 앞서, 파일을 본인이 사용하는 텍스트 에디터와 브라우저를 통해 연다.</li> + <li>프로그램을 실행시켜본다.("Submit Button"을 눌렀을 때, 정상적으로 실행이 되면 안된다)</li> +</ol> + +<div class="note"> +<p><strong>Note</strong>: You might well have your own version of the game example that doesn't work, which you might want to fix! We'd still like you to work through the article with our version, so that you can learn the techniques we are teaching here. Then you can go back and try to fix your example.</p> +</div> + +<p>여기서 구문 에러가 발생했을때 볼 수 있는 개발자 콘솔에 대해 살펴보고, 이를 통해 수정해보자. 이제부터 시작이다!</p> + +<h2 id="구문Syntax_에러_고치기">구문(Syntax) 에러 고치기</h2> + +<p>수업 앞쪽에서 간단한 자바스크립트 명령어를 <a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">developer tools JavaScript console</a> 에서 살펴보았다 (만약 모르겠다면 앞의 링크를 살펴보자). 좋은 것은, 브라우저의 자바스크립트 엔진이 구문에러가 발생할 대마다 에러메시지를 콘솔에게 던져준다. 자, 이제 시작해보자</p> + +<ol> + <li> 열려져 있는 <code>number-game-errors.html</code>이 있는 탭으로 가서 자바스크립트 콘솔창을 연다. 다음줄을 따라 에러메시지를 볼 수 있을 것이다.<img alt="" src="https://mdn.mozillademos.org/files/13496/not-a-function.png" style="display: block; margin: 0 auto;"></li> + <li>이는 쉬운 에러에 속하기 때문에, 브라우저가 해결하도록 팁등을 알려준다. (위의 캡처사진은 FireFox이지만, 아마 다른 브라우저에서도 비슷한 내용을 제공해준다). 왼쪽부터 살펴보면, + <ul> + <li>빨간색 "x"는 에러라는 것을 의미한다.</li> + <li>무엇이 잘못됬는지 알려준다. 여기서는 "TypeError: guessSubmit.addeventListener is not a function"</li> + <li>"Learn More" 링크는 다양한 내용이 있는 MDN 페이지와 연결해 에러의 의미를 설명해준다.</li> + <li>자바스크립트 파일의 이름으로 개발자툴의 디버거 탭을 연결한다. 이 링크를 따라가면, 에러가 발생한 정확한 위치를 찾을 수 있다.</li> + <li>에러가 발생한 줄번호와, 그 줄에서 몇번째 문자에 있는지 알려준다. 여기서는 86번줄, 앞에서 3번째 문자이다</li> + </ul> + </li> + <li>편집기에서 86번째 줄을 보자. + <pre class="brush: js">guessSubmit.addeventListener('click', checkGuess);</pre> + </li> + <li>"guessSubmit.addeventListener is not a function"라고 에러메시지가 뜨는걸로 보아, 아마 철자가 잘못되었을 것이다. 만약 철자가 애매하거나하면, MDN에서 찾아보는것이 좋을 것이다. 현재로 가장 좋은 방법은 검색엔진에서 "mdn <em>name-of-feature</em>" 를 검색하는 것이다. 예를들자면 다음을 살펴보자 -> <code><a href="/en-US/docs/Web/API/EventTarget/addEventListener">addEventListener()</a></code>.</li> + <li>여기서 살펴보며, 함수의 이름 철자가 틀려서 에러가 났음을 알수 있다. 자바스크립트와 같은 프로그래밍은 정확하기 때문에 한글자라도 틀리면 에러가 날 것이다. <code>addeventListener</code>를 <code>addEventListener</code>러 바꿈으로 에러는 해결된다. 고쳐보자.</li> +</ol> + +<div class="note"> +<p><strong>Note</strong>: See our <a href="/en-US/docs/Web/JavaScript/Reference/Errors/Not_a_function">TypeError: "x" is not a function</a> reference page for more details about this error.</p> +</div> + +<h3 id="반복되는_구문에러">반복되는 구문에러</h3> + +<ol> + <li>저장하고 새로고침해보자. 하지만 그래도 여전히 에러가 난다.</li> + <li>이제 숫자를 입력하고 "Submit guess" 버튼을 눌러보자. 그런데, 또 다른 에러가 나타났다!<img alt="" src="https://mdn.mozillademos.org/files/13498/variable-is-null.png" style="display: block; margin: 0 auto;"></li> + <li>이번에는 에러 메시지가 78번 줄에 "TypeError: lowOrHi is null" 라고 떳다. + <div class="note"><strong>Note</strong>: This error didn't come up as soon as the page was loaded because this error occurred inside a function (inside the <code>checkGuess() { ... }</code> block). As you'll learn in more detail in our later functions article, code inside functions runs in a separate scope to code outside functions. In this case, the code was not run and the error was not thrown until the <code>checkGuess()</code> function was run by line 86.</div> + <strong>Note</strong>: <code><a href="/en-US/docs/Glossary/Null">Null</a></code> is a special value that means "nothing", or "no value". So <code>lowOrHi</code> has been declared and initialised, but not with any meaningful value — it has no type or value.</li> + <li>78번줄은 다음 코드다. + <pre class="brush: js">lowOrHi.textContent = 'Last guess was too high!';</pre> + </li> + <li>이줄에서는 <code>lowOrHi</code>변수의<code> textContent</code>속성을 문자열로 지정하지만, <code>lowOrHi</code>가 어떤 역할을 하는지 포함하지 않았기 때문에 동작되지 않는다. 왜 그런지 살펴보면, 예제의 <code>lowOrHi</code>의 다른 예제를 보면 알 수 있다. 가장 가까이에 잇는 부분은 48번줄에서 찾을 수 있다. + <pre class="brush: js">var lowOrHi = document.querySelector('lowOrHi');</pre> + </li> + <li>여기서는 변수로 하여금 HTML안의 요소로 정보를 가지도록 하려고 한다. 이 줄이 실행되고 나서 값의 null인지도 확인해보자. 49번줄에 다음 코드를 추가해보자. + <pre class="brush: js">console.log(lowOrHi);</pre> + + <div class="note"> + <p><strong>Note</strong>: <code><a href="/en-US/docs/Web/API/Console/log">console.log()</a></code> is a really useful debugging function that prints a value to the console. So it will print the value of <code>lowOrHi</code> to the console as soon as we have tried to set it in line 48.</p> + </div> + </li> + <li>저장하고 새로고침해보면, 콘솔창에서 <code>console.log()</code> 의 결과를 볼 수 있을 것이다.<img alt="" src="https://mdn.mozillademos.org/files/13494/console-log-output.png" style="display: block; margin: 0 auto;"> 물론, <code>lowOrHi</code>'s값은 여전히 null이므로 48번줄은 문제가 있다고 볼 수 있다.</li> + <li>문제가 무엇인지 생각해보자. 49번줄 <code><a href="/en-US/docs/Web/API/Document/querySelector">document.querySelector()</a></code> 메소드는 CSS 선택자로금 선택되는 요소의 정보를 갖도록 만든다. 파일을 살펴보면, 다음과 같은 코드를 볼 수 있다. + <pre class="brush: js"><p class="lowOrHi"></p></pre> + </li> + <li>따라서 여기에 점(.) 으로 시작되는 클래스 선택자가 필요한 것이다 . 하지만 48번줄의 querySelector() 메소드에서는 바로 이 '점(.)' 이 없다. <code>lowOrHi</code>를 <code>.lowOrHi</code> 로 바꾸어 문제를 해결할 수 있다.</li> + <li>저장하고 새로고침하면, <code>console.log() </code>에서 우리가 원하는 <p> 요소를 반환할 것이다. 자, 이제 다른 에러가 해결되었다. <code>console.log()</code>를 지금 제거해도 되고 난중을 위해 나둬도 되니 알아서 하자.</li> +</ol> + +<div class="note"> +<p><strong>Note</strong>: See our <a href="/en-US/docs/Web/JavaScript/Reference/Errors/Unexpected_type">TypeError: "x" is (not) "y"</a> reference page for more details about this error.</p> +</div> + +<h3 id="세번씩_반복되는_구문에러">세번씩 반복되는 구문에러</h3> + +<ol> + <li>이제 프로그램을 계속 실행할수록, 성공횟수는 많아진다. 즉 프로그램이 종료될때까지 정확한 수를 추측하든, 횟수에 상관없이 완벽한 프로그램이 동작된다는 것이다.</li> + <li>여기서 프로그램에 처음에 보았던 똑같던 에러가 발생한다. "TypeError: resetButton.addeventListener is not a function"이라고! 하지만 이번에는 94번줄이라고 표시된다.</li> + <li>94번줄을 보면, 똑같은 실수를 하고 있다는 것을 쉽게 찾아볼 수 있다. 단지 <code>addeventListener</code> 를 <code>addEventListener</code> 로 철자만 주의해서 바꾸면 된다.</li> +</ol> + +<h2 id="논리Logic_에러">논리(Logic) 에러</h2> + +<p>이제, 프로그램은 잘 작동되지만, 몇 번 프로그램을 돌리면 추측해야 할 수가 항상 1이라는 것을 명백히 알 수 있다. 즉, 프로그램의 목표에 어긋난다는 것이다.</p> + +<p>이는 분명 어딘가에 프로그램 논리적으로 무슨 문제가 있다는 것이다.(물론, 에러가 검출되지도 않고, 잘 작동된다)</p> + +<ol> + <li><code>randomNumber</code> 변수를 찾고, 임의의 수를 처음으로 지정된 곳도 찾는다. 임의의 수가 저장된 부분은 아마 44번 줄 언저리일 것이다. + + <pre class="brush: js">var randomNumber = Math.floor(Math.random()) + 1;</pre> + 또한 한 게임이 끝나면 다시 임의의 수를 지정하는 부분은 아마 113번 줄 정도일 것이다.<br> + + <pre class="brush: js">randomNumber = Math.floor(Math.random()) + 1;</pre> + </li> + <li><code><font face="Open Sans, Arial, sans-serif">이 줄에서 문제가 발생되었는지 알기위해, </font>console.log()</code> 를 불러오자. 다음 코드를 앞선 두 코드 아래에 넣는 것도 잊지 말자. + <pre class="brush: js">console.log(randomNumber);</pre> + </li> + <li>저장하고, 새로고침하게되면 randomNumer 변수가 항상 1이 콘솔창에 표시되는 것을 알 수 있다.</li> +</ol> + +<h3 id="논리에_대한_고찰">논리에 대한 고찰</h3> + +<p>고치기 전에, 이 코드가 무슨 역할을 하는지 살펴보자. 먼저, 0과 1사이의 임의의 10진수를 생성하는 <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random">Math.random()</a> </code>을 살펴보자.</p> + +<pre class="brush: js">Math.random()</pre> + +<p>다음으로 가장 가까운 정수로 전달되는 <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/floor">Math.floor()</a></code><font face="Open Sans, arial, sans-serif">안의</font><code> Math.random()</code>의 결과는 넘어간다<code>.</code> 그러고 결과값에 1을 더한다.</p> + +<pre>Math.floor(Math.random()) + 1</pre> + +<p>0과 1사이의 임의의 10진수와 가장 가까운 수 중에 작은 수는 항상 0이므로, 여기서 1을 더하면 항상 1이 된다. 따라서 가까운 수를 찾기전에 임의수에 100을 곱해야 한다. 다음 코드는 곧 0과 99사이의 수를 나타낸다.</p> + +<pre class="brush: js">Math.floor(Math.random()*100);</pre> + +<p>그러므로 여기서 1을 더하게 되면, 우리가 원하는 1과 100사이의 수가 될 것이다.</p> + +<pre class="brush: js">Math.floor(Math.random()*100) + 1;</pre> + +<p>코드를 위와 같이 고치고, 저장 후 새로고침해보자. 그러면 프로그램은 우리가 생각하는 대로 작동될 것이다.</p> + +<h2 id="다른_일반적인_에러">다른 일반적인 에러</h2> + +<p>코드상에서 맞딱드릴 수 있는 에러는 여러가지가 있다. 이번 섹션은 이러한 에러들에 대해 말해줄 것이다.</p> + +<h3 id="SyntaxError_missing_before_statement">SyntaxError: missing ; before statement</h3> + +<p>이번 에러는 일반적으로 코드의 끝부분에 세미콜론이 빠졌을 때 발생하지만, 때로는 헷갈릴 때도 있다. 예를 들어 <code>checkGuess()</code> 함수안의 코드를 고칠때를 살펴보자.</p> + +<pre class="brush: js">var userGuess = Number(guessField.value);</pre> + +<p>이 코드를 다음코드로 바꾼다.</p> + +<pre class="brush: js">var userGuess === Number(guessField.value);</pre> + +<p>당연히 이 둘의 코드가 다르기때문에 오류가 발생했을 것이다. 즉, 대입 연산자(=, 값을 변수에 지정하도록 함)와 비교연산자(===, 어떤 값과 다른값을 비교할때 쓰며, true와false중 하나가 반환됨)를 함께 혼동해서 쓰면 안된다.</p> + +<div class="note"> +<p><strong>Note</strong>: See our <a href="/en-US/docs/Web/JavaScript/Reference/Errors/Missing_semicolon_before_statement">SyntaxError: missing ; before statement</a> reference page for more details about this error.</p> +</div> + +<h3 id="어떤_값을_입력해도_항상_성공표시가_뜬다.">어떤 값을 입력해도, 항상 성공표시가 뜬다.</h3> + +<p>이 또한, 앞처럼 대입연산자와 비교연산자를 혼동해서 사용한 경우이다. 예를들어, <code>checkGuess()</code>함수 안의 다음코드</p> + +<pre class="brush: js">if (userGuess === randomNumber) {</pre> + +<p>를</p> + +<pre class="brush: js">if (userGuess = randomNumber) {</pre> + +<p>로 바꾼다면, 조건문은 항상 참이므로, 프로그램은 항상 성공했다고 뜰 것이니 주의하자!</p> + +<h3 id="SyntaxError_missing_after_argument_list">SyntaxError: missing ) after argument list</h3> + +<p>이는 보통 함수나 메소드 호출의 끝부분에 괄호 닫는것을 빼먹은 것을 의미한다.</p> + +<div class="note"> +<p><strong>Note</strong>: See our <a href="/en-US/docs/Web/JavaScript/Reference/Errors/Missing_parenthesis_after_argument_list">SyntaxError: missing ) after argument list</a> reference page for more details about this error.</p> +</div> + +<h3 id="SyntaxError_missing_after_property_id">SyntaxError: missing : after property id</h3> + +<p>이 오류는 자바스립트의 객체가 잘못되었을 때 발생하지만, 다음의 경우에는 변경할 수 있다.</p> + +<pre class="brush: js">function checkGuess() {</pre> + +<p>-></p> + +<pre class="brush: js">function checkGuess( {</pre> + +<p>이는 브라우저로 하여금 함수안의 컨텐츠를 인자로 함수에게 넘겨주는 역할을 한다. 괄호에 주의하도록 하자!</p> + +<h3 id="SyntaxError_missing_after_function_body">SyntaxError: missing } after function body</h3> + +<p>일반적으로 함수나 조건문에서 중괄호를 닫지 않아서 발생한다. <code>checkGuess()</code> 함수의 아래부분의 중괄호를 닫지않아서 에러가 발생한다.</p> + +<h3 id="SyntaxError_expected_expression_got_string_or_SyntaxError_unterminated_string_literal">SyntaxError: expected expression, got '<em>string</em>' or SyntaxError: unterminated string literal</h3> + +<p>이는 보통 문자열을 열거나 닫는 따옴표를 생략한 경우 에러가 발생한다.위의 첫번재 에러를 살펴보면, <em>string은</em> 문자열이 시작하는 부분에서 따옴표 대신 브라우저가 검색한 예상치 못한 문자열로 대체된다. 두번째 에러는 따옴표로 문자열이 끝나지 못했기 때문에 발생했다.</p> + +<p>모든 경우의 에러를 보았을 때, 지금까지 살펴본 예제에 어떻게 씨름했는지 생각해보자. 에러가 발생하면 , 발생된 줄 번호를 보고, 그 줄로 이동해 무엇이 잘못되었는지 살펴보는것이다. 이 오류가 반드시 해당 라인에 있는 것은 아니며, 위에서 언급되어진 문제로 인해 오류가 발생하지 않을 수도 있다는 점을 명심하자!</p> + +<div class="note"> +<p><strong>Note</strong>: See our <a href="/en-US/docs/Web/JavaScript/Reference/Errors/Unexpected_token">SyntaxError: Unexpected token</a> and <a href="/en-US/docs/Web/JavaScript/Reference/Errors/Unterminated_string_literal">SyntaxError: unterminated string literal</a> reference pages for more details about these errors.</p> +</div> + +<h2 id="요약">요약</h2> + +<p>자, 지끔까지 자바스크립트 프로그램에서의 에러의 특징에 대해 살펴보았다.물론, 코드상의 에러가 항상 간단한 것만은 아니다. 하지만 최소한 업무량은 줄어줄 것이며, 작업도 빠르게 마치도록 해줄 것이다.</p> + +<h2 id="더보기">더보기</h2> + +<div> +<ul> + <li>여기서 소개하지 못한 에러들도 많으니, 다음 링크에서 정보들을 찾아보며 그때그때 자세히 알아보자l — <a href="/en-US/docs/Web/JavaScript/Reference/Errors">JavaScript error reference</a>.</li> + <li>이것을 보고도 에러를 해결하지 힘들다면 <span class="short_text" id="result_box" lang="ko"><span>MDN 토론 포럼 </span></span>로 에러를 보내면 도와줄 것이다. 또한 다른 코드를 살펴보는 것도 좋다.</li> +</ul> +</div> + +<p>{{PreviousMenuNext("Learn/JavaScript/First_steps/A_first_splash", "Learn/JavaScript/First_steps/Variables", "Learn/JavaScript/First_steps")}}</p> diff --git a/files/ko/learn/javascript/howto/index.html b/files/ko/learn/javascript/howto/index.html new file mode 100644 index 0000000000..7af2a007be --- /dev/null +++ b/files/ko/learn/javascript/howto/index.html @@ -0,0 +1,294 @@ +--- +title: Solve common problems in your JavaScript code +slug: Learn/JavaScript/Howto +tags: + - 자바스크립트 + - 초보자 + - 학습 +translation_of: Learn/JavaScript/Howto +--- +<div>{{LearnSidebar}}</div> + +<div>다음의 링크들은 당신의 자바스크립트 코드가 정상적으로 작동할 수 있게 고쳐야되는 흔한 문제들의 해결책을 제시한다.</div> + +<h2 id="초보자들의_흔한_실수들">초보자들의 흔한 실수들</h2> + +<h3 id="스펠링과_대소문자를_제대로_해라">스펠링과 대소문자를 제대로 해라</h3> + +<p>코드가 작동하지 않거나 브라우저가 무언가가 undefined라고 불평하면 모든 변수 이름, 함수 이름 등을 정확하게 입력했는지 확인하십시오. </p> + +<p>문제를 일으키는 몇 가지 일반적인 내장 브라우저 함수는 다음과 같습니다.</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">올바른</th> + <th scope="col">잘못된</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>getElementsByTagName()</code></td> + <td><code>getElementbyTagName()</code></td> + </tr> + <tr> + <td><code>getElementsByName()</code></td> + <td><code>getElementByName()</code></td> + </tr> + <tr> + <td><code>getElementsByClassName()</code></td> + <td><code>getElementByClassName()</code></td> + </tr> + <tr> + <td><code>getElementById()</code></td> + <td><code>getElementsById()</code></td> + </tr> + </tbody> +</table> + +<h3 id="세미콜론의_위치">세미콜론의 위치</h3> + +<p>세미콜론의 위치가 잘못 되지 않았는지 확인하세요. 예를들어:</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">올바른</th> + <th scope="col">잘못된</th> + </tr> + <tr> + <td><code>elem.style.color = 'red';</code></td> + <td><code>elem.style.color = 'red;'</code></td> + </tr> + </thead> +</table> + +<h3 id="함수">함수</h3> + +<p>함수와 관련하여 실수할 수 있는 것들이 많이 있습니다.</p> + +<p>가장 흔한 실수는 함수를 선언하고 어디서도 호출하지 않는 것입니다. 예를 들어:</p> + +<pre class="brush: js">function myFunction() { + alert('This is my function.'); +};</pre> + +<p>위 코드는 호출하지 않는 이상 아무것도 하지 않습니다.</p> + +<pre class="brush: js">myFunction();</pre> + +<h4 id="함수_스코프">함수 스코프</h4> + +<p><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions#Function_scope_and_conflicts">함수는 각자의 스코프가 있음</a>을 명심하세요 — 변수를 전역으로 선언하거나 함수에서 <a href="/en-US/docs/Learn/JavaScript/Building_blocks/Return_values">값을 리턴</a>하지 않는한 함수 밖에서 함수 내부에 설정된 변수 값에 접근 할 수 없습니다. (즉, 어떠한 함수 내에서도 접근 안됨)</p> + +<h4 id="리턴_문_이후_코드_실행">리턴 문 이후 코드 실행</h4> + +<p>함수 밖으로 값을 리턴할 때, 자바스크립트 인터프리터가 함수를 완전히 빠져나감을 명심하세요. — 리턴 문 이후에 선언된 코드는 절대로 실행되지 않습니다.</p> + +<p>사실, 몇몇 브라우저들은 (파이어폭스 처럼) 리턴 문 이후에 코드가 있다면 개발자 콘솔에 에러 메세지를 줍니다. 파이어폭스는 "unreachable code after return statement" 라고 알려줍니다.</p> + +<h3 id="오브젝트_표기_vs_일반적_할당">오브젝트 표기 vs 일반적 할당</h3> + +<p>보통 자바스크립테어서 무언가를 할당하려고 할때, 단일 등호기호를 사용합니다. 예:</p> + +<pre class="brush: js">const myNumber = 0;</pre> + +<p>하지만, 이 방법은 <a href="/en-US/docs/Learn/JavaScript/Objects">오브젝트</a>에선 동작하지 않습니다. — 오브젝트에선 멤버와 값 사이를 콜론으로 구분하고, 각 멤버들은 콤마로 구분합니다, 예를 들어:</p> + +<pre class="brush: js">const myObject = { + name: 'Chris', + age: 38 +}</pre> + +<h2 id="기본_정의">기본 정의</h2> + +<div class="column-container"> +<div class="column-half"> +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/What_is_JavaScript#A_high-level_definition">자바스크립트란 무엇인가?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Variables#What_is_a_variable">변수는 무엇인가?</a> </li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Strings">문자열은 무엇인가?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Arrays#What_is_an_Array">배열은 무엇인가?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Looping_code">루프는 무엇인가?</a></li> +</ul> +</div> + +<div class="column-half"> +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions">함수는 무엇인가?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events">What is an event?</a> <a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events">이벤트는 무엇인가?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Basics#Object_basics">오브젝트는 무엇인가?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/JSON#No_really_what_is_JSON">JSON은 무엇인가?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Introduction#What_are_APIs">web API는 무엇인가?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Manipulating_documents#The_document_object_model">DOM은 무엇인가?</a></li> +</ul> +</div> +</div> + +<h2 id="Basic_use_cases">Basic use cases</h2> + +<div class="column-container"> +<div class="column-half"> +<h3 id="General">General</h3> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/What_is_JavaScript#How_do_you_add_JavaScript_to_your_page">How do you add JavaScript to your page?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/What_is_JavaScript#Comments">How do you add comments to JavaScript code?</a></li> +</ul> + +<h3 id="Variables">Variables</h3> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Variables#Declaring_a_variable">How do you declare a variable?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Variables#Initializing_a_variable">How do you initialize a variable with a value?</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/First_steps/Variables#Updating_a_variable">How do you update a variable's value?</a> (also see <a href="/en-US/docs/Learn/JavaScript/First_steps/Math#Assignment_operators">Assignment operators</a>)</li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/First_steps/Variables#Variable_types">What data types can values have in JavaScript?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Variables#Loose_typing">What does 'loosely typed' mean?</a></li> +</ul> + +<h3 id="Math">Math</h3> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Math#Types_of_numbers">What types of number do you have to deal with in web development?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Math#Arithmetic_operators">How do you do basic math in JavaScript?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Math#Operator_precedence">What is operator precedence, and how is it handled in JavaScript?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Math#Increment_and_decrement_operators">How do you increment and decrement values in JavaScript?</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/First_steps/Math#Comparison_operators">How do you compare values in JavaScript?</a> (e.g. to see which one is bigger, or to see if one value is equal to another).</li> +</ul> + +<h3 id="Strings">Strings</h3> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Strings#Creating_a_string">How do you create a string in JavaScript?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Strings#Single_quotes_versus_double_quotes">Do you have to use single quotes or double quotes?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Strings#Escaping_characters_in_a_string">How do you escape characters in strings?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Strings#Concatenating_strings">How do you join strings together?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Strings#Numbers_versus_strings">Can you join strings and numbers together?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Useful_string_methods#Finding_the_length_of_a_string">How do you find the length of a string?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Useful_string_methods#Retrieving_a_specific_string_character">How you find what character is at a certain position in a string?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Useful_string_methods#Finding_a_substring_inside_a_string_and_extracting_it">How do you find and extract a specific substring from a string?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Useful_string_methods#Changing_case">How do you change the case of a string?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Useful_string_methods#Updating_parts_of_a_string">How do you replace one specific substring with another?</a></li> +</ul> +</div> + +<div class="column-half"> +<h3 id="Arrays">Arrays</h3> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Arrays#Creating_an_array">How do you create an array?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Arrays#Accessing_and_modifying_array_items">How do you access and modify the items in an array?</a> (this includes multidimensional arrays)</li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Arrays#Finding_the_length_of_an_array">How do you find the length of an array?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Arrays#Adding_and_removing_array_items">How you add and remove array items?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/Arrays#Converting_between_strings_and_arrays">How do you split a string into array items, or join array items into a string?</a></li> +</ul> + +<h3 id="Debugging_JavaScript">Debugging JavaScript</h3> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/First_steps/What_went_wrong#Types_of_error">What are the basic types of error?</a></li> + <li><a href="/en-US/docs/Learn/Common_questions/What_are_browser_developer_tools">What are browser developer tools, and how do you access them?</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/JavaScript#The_Console_API">How do you log a value to the JavaScript console?</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/JavaScript#Using_the_JavaScript_debugger">How do you use breakpoints, and other JavaScript debugging features?</a></li> +</ul> + +<p>For more information on JavaScript debugging, see <a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/JavaScript">Handling common JavaScript problems</a>; also see <a href="/en-US/docs/Learn/JavaScript/First_steps/What_went_wrong#Other_common_errors">Other common errors</a> for a description of common errors.</p> + +<h3 id="Making_decisions_in_code">Making decisions in code</h3> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/conditionals">How do you execute different blocks of code, depending on a variable's value or other condition?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/conditionals#if_..._else_statements">How do you use if ...else statements?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/conditionals#Nesting_if_..._else">How do nest one decision block inside another?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/conditionals#Logical_operators_AND_OR_and_NOT">How do you use AND, OR, and NOT operators in JavaScript?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/conditionals#switch_statements">How do you conveniently handle a large number of choices for one condition?</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/conditionals#Ternary_operator">How do you use a ternary operator to make a quick choice between two options based on a true or false test?</a></li> +</ul> + +<h3 id="Loopingiteration">Looping/iteration</h3> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Looping_code">How do you run the same bit of code over and over again?</a></li> + <li><a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Looping_code#Exiting_loops_with_break">How do you exit a loop before the end if a certain condition is met?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Looping_code#Skipping_iterations_with_continue">How do you skip to the next iteration of a loop if a certain condition is met?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Looping_code#while_and_do_..._while">How do you use while and do ... while loops?</a></li> + <li>How to iterate over the elements in an array</li> + <li>How to iterate over the elements in a multidimensional array</li> + <li>How to iterate over the members in an object</li> + <li>How to iterate over the members of an object nested inside an array</li> +</ul> +</div> +</div> + +<h2 id="Intermediate_use_cases">Intermediate use cases</h2> + +<div class="column-container"> +<div class="column-half"> +<h3 id="Functions">Functions</h3> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions#Built-in_browser_functions">How do you find functions in the browser?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions#Functions_versus_methods">What is the difference between a function and a method?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Build_your_own_function">How do you create your own functions?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions#Invoking_functions">How do you run (call, or invoke) a function?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions#Anonymous_functions">What is an anonymous function?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions#Function_parameters">How do you specify parameters (or arguments) when invoking a function?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Functions#Function_scope_and_conflicts">What is function scope?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Return_values">What are return values, and how do you use them?</a></li> +</ul> + +<h3 id="Objects">Objects</h3> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Basics#Object_basics">How do you create an object?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Basics#Dot_notation">What is dot notation?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Basics#Bracket_notation">What is bracket notation?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Basics#Setting_object_members">How do you get and set the methods and properties of an object?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Basics#What_is_this">What is <code>this</code>, in the context of an object?</a></li> + <li><a href="/docs/Learn/JavaScript/Objects/Object-oriented_JS#Object-oriented_programming_from_10000_meters">What is object-oriented programming?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object-oriented_JS#Constructors_and_object_instances">What are constructors and instances, and how do you create them?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object-oriented_JS#Other_ways_to_create_object_instances">What different ways are there to create objects in JavaScript?</a></li> +</ul> + +<h3 id="JSON">JSON</h3> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/JSON#JSON_structure">How do you structure JSON data, and read it from JavaScript?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/JSON#Loading_our_JSON">How can you load a JSON file into a page?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/JSON#Converting_between_objects_and_text">How do you convert a JSON object to a text string, and back again?</a></li> +</ul> +</div> + +<div class="column-half"> +<h3 id="Events">Events</h3> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_handler_properties">What are event handlers and how do you use them?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events#Inline_event_handlers_%E2%80%94_don%27t_use_these">What are inline event handlers?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events#addEventListener()_and_removeEventListener()">What does the <code>addEventListener()</code> function do, and how do you use it?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events#What_mechanism_should_I_use">Which mechanism should I use to add event code to my web pages?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_objects">What are event objects, and how do you use them?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events#Preventing_default_behaviour">How do you prevent default event behaviour?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_bubbling_and_capture">How do events fire on nested elements? (event propagation, also related — event bubbling and capturing)</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_delegation">What is event delegation, and how does it work?</a></li> +</ul> + +<h3 id="Object-oriented_JavaScript">Object-oriented JavaScript</h3> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object_prototypes">What are object prototypes?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object_prototypes#The_constructor_property">What is the constructor property, and how can you use it?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object_prototypes#Modifying_prototypes">How do you add methods to the constructor?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Inheritance">How do you create a new constructor that inherits its members from a parent constructor?</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Inheritance#Object_member_summary">When should you use inheritance in JavaScript?</a></li> +</ul> + +<h3 id="Web_APIs">Web APIs</h3> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Manipulating_documents#Active_learning_Basic_DOM_manipulation">How do you manipulate the DOM (e.g. adding or removing elements) using JavaScript?</a></li> +</ul> + +<p> </p> +</div> +</div> diff --git a/files/ko/learn/javascript/index.html b/files/ko/learn/javascript/index.html new file mode 100644 index 0000000000..b45501e751 --- /dev/null +++ b/files/ko/learn/javascript/index.html @@ -0,0 +1,70 @@ +--- +title: JavaScript - 동적인 클라이언트측 스크립트 언어 +slug: Learn/JavaScript +tags: + - Beginner + - JavaScript + - 입문 + - 입문자 + - 자바스크립트 + - 자바스크립트 입문자 +translation_of: Learn/JavaScript +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">{{Glossary("JavaScript")}} 는 웹 페이지의 복잡한 것들을 구현할 수 있는 프로그래밍 언어입니다. 웹페이지는 단순히 변하지 않고 정적인 정보들만 보여주는 것 이상의 일을 합니다. 시간의 흐름에 따라 업데이트 되는 콘텐츠, 동적인 지도와 움직이는 2D/3D 그래픽, 또는 스크롤 가능한 비디오 쥬크박스들과 여러 가지들을 보여줍니다. 여러분은 '아마도 JavaScript 그 일들을 하고 있겠구나'라고 생각하실 수 있습니다.</p> + +<h2 id="학습_과정">학습 과정</h2> + +<p>JavaScript 는 HTML 이나 CSS 와 같은 관련 기술들보다 배우기가 더 어렵습니다. JavaScript 에 입문하기 전에, 적어도 아래의 두가지 기술을 먼저 배우고, 아마도 다른 것들도 배우는 것이 좋습니다. 다음 과정들을 통해 시작하세요.</p> + +<ul> + <li><a href="/ko/docs/Learn/Getting_started_with_the_web">Web과 함께 시작하기</a></li> + <li><a href="/ko/docs/Learn/HTML/Introduction_to_HTML">HTML 소개</a></li> + <li><a href="/ko/docs/Learn/CSS/Introduction_to_CSS">CSS 소개</a></li> +</ul> + +<p>다른 프로그래밍 언어를 배웠던 경험이 있다면 도움이 될 수도 있습니다.</p> + +<p>JavaScript 의 기본적인 것들이 익숙해진 이후에, 여러분은 더 고급 주제들을 배울 준비가 되어 있어야 합니다. 예를 들면 다음과 같습니다.</p> + +<ul> + <li>JavaScript 심화, <a href="/ko/docs/Web/JavaScript/Guide">자바스크립트 안내서</a></li> + <li><a href="/ko/docs/Web/API">웹 API 참조문서</a></li> +</ul> + +<h2 id="과정">과정</h2> + +<p>이 주제에는 다음 과정들이 제안된 순서대로 포함되어 있습니다.</p> + +<dl> + <dt><a href="/ko/docs/Learn/JavaScript/First_steps">자바스크립트 첫걸음</a></dt> + <dd>JavaScript 과정에서, JavaScript를 이용해 첫번째 경험을 쌓기 이전에 "JavaScript 는 무엇인가요?", "어떻게 생겼나요?", 그리고 "그것으로 무엇을 할 수 있죠?" 와 같은 질문에 대답 할 수 있어야 합니다. 그 이후에, 변수, 문자열, 숫자 그리고 배열과 같은 JavaScript 의 기능에 대해 살펴봅시다.</dd> + <dt><a href="/ko/docs/Learn/JavaScript/Building_blocks">JavaScript 구성 요소</a></dt> + <dd>이 과정에서는, 조건문, 반복문, 함수, 그리고 이벤트와 같이 일반적으로 쓰이며 괄호로 감싸여진 형태인 JavaScript 의 핵심적인 기본 기능들을 살펴볼 것입니다. 여러분은 이미 이것들에 대해 이미 보셨겟지만, 그저 지나쳤을 것이니, 우리는 이것에 대해 자세히 살펴볼 것입니다.</dd> + <dt><a href="/ko/docs/Learn/JavaScript/Objects">JavaScript 객체 소개</a></dt> + <dd>JavaScript 에서는 문자열과 배열같은 핵심적인 JavaScript 기능부터 JavaScript 보다 위에 작성된 브라우저의 API 까지 거의 대부분이 객체입니다. 심지어 관련 함수와 변수들을 효율적인 패키지로 캡슐화하기 위해 객체를 만들 수도 있습니다. 여러분이 언어에 대한 이해도를 높이고 효율적으로 코드를 작성하기 위해서라면 JavaScript 의 객체 지향적인 특성을 이해하는 것이 중요합니다. 따라서 우리는 이 과정을 통해 여러분을 도와드릴 것입니다. 여기에서는 객체 이론과 문법에 대해 설명하고 어떻게 객체를 만들고, JSON 데이터가 무엇이고 어떻게 작동하는지에 대해 설명합니다.</dd> + <dt><a href="/ko/docs/Learn/JavaScript/Asynchronous">비동기적 JavaScript</a> </dt> + <dd> + <p>이 부분에서 우리는 Javascript의 비동기적 실행이 왜 중요한지, 서버에서 리소스를 가져올때와 같은 시간지연을 유발하는 동작들을 어떻게 효과적으로 다룰지등에 대해 살펴봅니다.</p> + </dd> + <dt><a href="/ko/docs/Learn/JavaScript/Client-side_web_APIs">Client-side web APIs</a></dt> + <dd>클라이언트측의 웹사이트나 응용프로그램을 위해 JavaScript 를 작성하는 경우, 여러분은 브라우저와 운영체제 또는 다른 웹사이트의 데이터를 위한 API를 사용하기 전에 이상한 길에 빠지지 않을 겁니다. 이번 과정에서는 API 가 무엇인지, 그리고 개발 도중 자주 접하게 될 가장 보편적인 API들을 사용하는 방법에 대해 알아 볼 것입니다.</dd> +</dl> + +<h2 id="일반적인_JavaScript_문제_해결">일반적인 JavaScript 문제 해결</h2> + +<p><a href="/ko/docs/Learn/JavaScript/Howto">JavaScript 를 이용한 보편적인 문제 해결</a> 은 웹페이지를 만들 때 발생하는 일반적인 문제들을 JavaScript 로 해결하는 방법에 대한 링크들을 제공합니다.</p> + +<h2 id="관련_항목">관련 항목</h2> + +<dl> + <dt><a href="/ko/docs/Web/JavaScript">JavaScript on MDN</a></dt> + <dd>JavaScript 의 핵심적인 문서입니다. 여기서 JavaScript 언어의 모든 측면에 대해 넓은 참조 문서들과 JavaScript 경험자들을 위한 심화 튜토리얼들을 찾을 수 있습니다.</dd> + <dt><a href="https://learnjavascript.online/">JavaScript 배우기</a></dt> + <dd>Web 개발자 지망생을 위한 훌륭한 자료 — 짧은 강좌와 대화형 테스트, 자동화된 평가로 지도하는 인터랙티브 환경에서 JavaScript를 배웁니다. 처음 40개 강좌 는 무료이며, 한번의 작은 금액 지불로 전체코스를 수강할 수 있습니다.</dd> + <dt><a href="https://exlskills.com/learn-en/courses/javascript-fundamentals-basics_javascript">EXLskills의 JavaScript 기초</a></dt> + <dd>EXLskills의 오픈소스 코스로 JavaScript를 무료로 배우세요 JS로 어플리케이션 제작을 시작하는데 필요한 모든것을 배울수 있습니다.</dd> + <dt><a href="https://www.youtube.com/user/codingmath">Coding math</a></dt> + <dd>프로그래머가 되기 위해 이해해야 하는 수학을 가르치는 훌륭한 비디오 튜토리얼 시리즈 by <a href="https://twitter.com/bit101">Keith Peters</a>.</dd> +</dl> diff --git a/files/ko/learn/javascript/objects/basics/index.html b/files/ko/learn/javascript/objects/basics/index.html new file mode 100644 index 0000000000..4220f9bafc --- /dev/null +++ b/files/ko/learn/javascript/objects/basics/index.html @@ -0,0 +1,268 @@ +--- +title: JavaScript 객체 기본 +slug: Learn/JavaScript/Objects/Basics +tags: + - API + - this + - 객체 + - 객체 리터럴 + - 괄호 표기법 + - 구문 + - 배우기 + - 이론 + - 인스턴스 + - 입문자 + - 자바스크립트 + - 점 표기법 + - 코딩스크립트 +translation_of: Learn/JavaScript/Objects/Basics +--- +<div>{{LearnSidebar}}</div> + +<div>{{NextMenu("Learn/JavaScript/Objects/Object-oriented_JS", "Learn/JavaScript/Objects")}}</div> + +<p class="summary">이 글에서는 JavaScript 객체와 관련된 기본적인 문법을 살펴보고 이전 코스에서 학습해서 이미 알고 있는 JavaScript 의 특징들과 우리가 이미 사용하고 있는 기능들이 이미 객체와 관련되어 있다는 사실을 다시 한번 복습할 것입니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">사전 지식:</th> + <td>컴퓨터와 관련된 기본지식, HTML 과 CSS, 그리고 JavaScript 에 대한 기본 지식 (<a href="/ko/docs/Learn/JavaScript/First_steps">JavaScript 첫걸음</a> 및 <a href="/ko/docs/Learn/JavaScript/Building_blocks">JavaScript 구성요소</a> 참조).</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>객체지향 프로그래밍에 대한 기본 이론을 이해하고, JavaScript 에서 객체가 어떻게 처리되는지("대부분이 객체임") 학습 후, JavaScript 객체를 실제로 이용하는 방법에 대해 알게되는 것을 목표로 합니다.</td> + </tr> + </tbody> +</table> + +<h2 id="객체_기본">객체 기본</h2> + +<p>객체는 관련된 데이터와 함수(일반적으로 여러 데이터와 함수로 이루어지는데, 객체 안에 있을 때는 보통 프로퍼티와 메소드라고 부릅니다)의 집합입니다. 예제를 통해서 실제 객체가 무엇인지 알아보도록 합시다.</p> + +<p>시작하기에 앞서, <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/introduction/oojs.html">oojs.html</a> 파일의 복사본을 로컬 환경에 만듭니다. 이 파일은 우리가 작성한 소스코드를 포함하는 작은 {{HTMLElement("script")}} 요소를 포함하고 있습니다. 우리는 기본 객체 문법을 탐구하기 위한 기반으로 이 파일을 사용할 것입니다. 예제를 제대로 따라하려면 반드시 <a href="/ko/docs/Learn/Common_questions/What_are_browser_developer_tools#The_JavaScript_console">개발자 도구 JavaScript 콘솔</a>을 열어두고, 몇몇 명령어를 직접 입력할 준비가 되어있어야 합니다.</p> + +<p>여타 JavaScript 의 요소들과 마찬가지로, 객체를 생성하는 것은 변수를 정의하고 초기화하는 것으로 시작합니다. 아래의 JavaScript 코드를 oojs.html 파일의 script tag 사이에 입력하고 저장 한 후, 리로드 해보세요.</p> + +<pre class="brush: js">var person = {};</pre> + +<p>이제 JS 콘솔에 <code>person</code> 을 입력하면 다음과 같은 결과를 보게됩니다.</p> + +<pre class="brush: js">[object Object]</pre> + +<p>축하합니다, 여러분은 벌써 첫 번째 객체를 생성하였습니다. 하지만 텅 빈 객체여서 우린 이걸로 뭘 할 수는 없습니다. 자, 이제 이 오브젝트를 다음과 같이 고쳐봅시다.</p> + +<pre class="brush: js">var person = { + name: ['Bob', 'Smith'], + age: 32, + gender: 'male', + interests: ['music', 'skiing'], + bio: function() { + alert(this.name[0] + ' ' + this.name[1] + ' is ' + this.age + ' years old. He likes ' + this.interests[0] + ' and ' + this.interests[1] + '.'); + }, + greeting: function() { + alert('Hi! I\'m ' + this.name[0] + '.'); + } +}; +</pre> + +<p>저장 후 리로드 한 다음에 아래의 내용을 브라우저 개발자 도구의 JavaScript 콘솔에 입력해보세요.</p> + +<pre class="brush: js">person.name +person.name[0] +person.age +person.interests[1] +person.bio() +person.greeting()</pre> + +<p>자, 이제 당신은 객체에 포함된 데이터와 함수를 갖게 되었으며, 이것들을 간단하고 멋진 문법을 통해 사용할 수 있게되었습니다!</p> + +<div class="note"> +<p><strong>Note</strong>: 만약 여기까지 진행하는데 어려움이 있다면, 제가 만들어놓은 파일과 비교해보세요 — <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/introduction/oojs-finished.html">oojs-finished.html</a> (그리고 <a href="http://mdn.github.io/learning-area/javascript/oojs/introduction/oojs-finished.html">실행되는 예제도 보세요</a>). Live 버전에서는 텅빈 화면만 보이겠지만, 그게 정상입니다 — 다시, 개발자도구를 열고 객체 구조를 들여다보기 위해 위에 언급된 명령어를 입력해보세요.</p> +</div> + +<p>자, 이제 뭘 해볼까요? 객체는 각기 다른 이름(위의 예에서는 <code>name</code> 과 <code>age</code>)과 값(예제에서, <code>['Bob', 'Smith']</code> 과 <code>32</code>)을 갖는 복수개의 멤버로 구성됩니다. 한 쌍의 이름과 값은 ',' 로 구분되야 하고, 이름과 값은 ':' 으로 분리됩니다. 결국 문법은 아래와 같은 패턴이 됩니다.</p> + +<pre class="brush: js">var objectName = { + member1Name: member1Value, + member2Name: member2Value, + member3Name: member3Value +};</pre> + +<p>객체를 구성하는 멤버의 값은 어떤 것이라도 될 수 있습니다. 우리가 만든 person 객체는 문자열, 숫자, 배열 두개와 두개의 함수를 가지고 있습니다. 처음 4개의 아이템은 데이터 아이템인데, 이걸 객체의 <strong>프로퍼티(속성) </strong>라고 부릅니다. 끝에 두개의 아이템은 함수인데 이 함수를 통해 데이터를 가지고 뭔가 일을 할 수 있게 됩니다. 이걸 우리는 <strong>메소드</strong> 라고 부릅니다.</p> + +<p>이런 객체는 객체 리터럴(<strong>object literal)</strong> 이라고 부릅니다. 객체를 생성할 때 컨텐츠를 그대로 대입합니다. 객체 리터럴은 클래스로부터 생성하는 방식과는 다릅니다. 이 방식은 뒤에서 살펴보게 될겁니다.</p> + +<p>객체 리터럴을 사용해서 객체를 생성하는 것은 연속된 구조체나 연관된 데이터를 일정한 방법으로 변환하고자 할 때 많이 쓰이는 방법입니다. 예를 들면 서버에게 주소를 데이터베이스에 넣어달라고 요청하는 경우입니다. 각 아이템들을 하나 하나 개별 전송하는 것보다, 하나의 객체를 전송하는 것이 훨씬 효율적입니다. 또 각 아이템들을 이름으로 구분해서 사용하기 원할 때도 배열을 사용하는 것보다 훨씬 쉽습니다.</p> + +<h2 id="점_표기법">점 표기법</h2> + +<p>위에서, 우리는 객체의 프로퍼티와 메소드를 <strong>점 표기법</strong>을 통해 접근했습니다. 객체 이름(person)은 <strong>네임스페이스</strong>처럼 동작합니다. 객체내에 <strong>캡슐화되어있는</strong>것에 접근하려면 먼저 점을 입력해야합니다. 그 다음 점을 찍고 접근하고자 하는 항목을 적습니다. 간단한 프로퍼티의 이름일 수도 있을 것이고, 배열의 일부이거나 객체의 메소드를 호출할 수도 있습니다.</p> + +<pre class="brush: js">person.age +person.interests[1] +person.bio()</pre> + +<h3 id="하위_namespaces">하위 namespaces</h3> + +<p>다른 객체를 객체 멤버의 값으로 갖는 것도 가능합니다. 예를 들면, 다음과 같은 name 멤버를 </p> + +<pre class="brush: js">name: ['Bob', 'Smith'],</pre> + +<p>아래와 같이 바꿔봅시다.</p> + +<pre class="brush: js">name : { + first: 'Bob', + last: 'Smith' +},</pre> + +<p>자, 이제 우리는 성공적으로 <strong>하위 namespace</strong> 를 만들었습니다. 복잡해보이지만, 사실 그렇지도 않습니다. 이 속성을 사용하려면 그저 끝에 다른 점을 하나 찍어주기만 하면 됩니다. JS 콘솔에서 아래와 같이 입력해보세요.</p> + +<pre class="brush: js">person.name.first +person.name.last</pre> + +<p><strong>중요</strong>: 객체의 속성이 바뀌었으니까, 기존 메소드 코드를 바꿔 줘야 합니다. 기존 코드를</p> + +<pre class="brush: js">name[0] +name[1]</pre> + +<p>아래와 같이 바꿔줘야 합니다.</p> + +<pre class="brush: js">name.first +name.last</pre> + +<p>그렇지 않으면 기존 메소드는 더 이상 동작하지 않을 것입니다.</p> + +<h2 id="괄호_표기법">괄호 표기법</h2> + +<p>객체의 프로퍼티에 접근하는 다른 방법으로 괄호 표기법을 사용하는 것이 있습니다. 다음과 같이 사용하는 대신</p> + +<pre class="brush: js">person.age +person.name.first</pre> + +<p>이렇게 사용할 수 있습니다.</p> + +<pre class="brush: js">person['age'] +person['name']['first']</pre> + +<p>이런 방식은 배열 속에 있는 항목에 접근하는 방법과 매우 유사해 보이는데 실제로도 이는 기본적으로 동일한 것입니다. 한 항목을 선택하기 위해 인덱스 숫자를 이용하는 대신에 각 멤버의 값들과 연결된 이름을 이용합니다. 객체가 간혹 <strong>연관배열 (associative arrays</strong>)이라고 불리는 것이 당연합니다. 연관배열은 배열이 숫자를 값에 연결하는 것과 같은 방법으로 스트링을 값에 매핑합니다.</p> + +<h2 id="객체_멤버_설정하기">객체 멤버 설정하기</h2> + +<p>지금까지는 객체 멤버를 단순히 가져오기만(또는 <strong>반환</strong>) 했습니다. 설정할 멤버를 간단히 명시하여(점이나 대괄호 표기법을 사용) 객체 멤버의 값을 <strong>설정</strong>(갱신)하는 것도 물론 가능합니다.</p> + +<pre class="brush: js">person.age = 45; +person['name']['last'] = 'Cratchit';</pre> + +<p>위의 코드를 입력한 다음, 객체 멤버값을 아래와 같이 다시 확인해봅시다.</p> + +<pre class="brush: js">person.age +person['name']['last']</pre> + +<p>객체 멤버를 설정하는 것은 단순히 기존에 존재하는 프로퍼티나 메소드로 값을 설정하는 것 뿐 아니라, 완전히 새로운 멤버를 생성할 수도 있습니다. JS 콘솔에서 아래 내용을 입력해보세요.</p> + +<pre class="brush: js">person['eyes'] = 'hazel'; +person.farewell = function() { alert("Bye everybody!"); }</pre> + +<p>자, 이제 새로운 멤버를 테스트해보세요.</p> + +<pre class="brush: js">person['eyes'] +person.farewell()</pre> + +<p>대괄호 표현의 이점 중 하나는 멤버의 값을 동적으로 변경할 수 있을 뿐아니라, 멤버 이름까지도 동적으로 사용할 수 있다는 것입니다. 자, 만약 사용자가 두개의 텍스트 입력을 통해서 people 데이터에 커스텀 값을 넣고 싶어한다고 가정해봅시다. 그 값은 다음과 같이 얻어올 수 있을겁니다.</p> + +<pre class="brush: js">var myDataName = nameInput.value; +var myDataValue = nameValue.value;</pre> + +<p>이제 <code>person</code> 객체에 다음과 같이 새 멤버의 이름과 값을 추가할 수 있습니다.</p> + +<pre class="brush: js">person[myDataName] = myDataValue;</pre> + +<p>자, 제대로 동작하는지 보려면 아래와 같이 <code>person</code> 객체에 대괄호를 붙여서 확인해보면 됩니다.</p> + +<pre class="brush: js">var myDataName = 'height'; +var myDataValue = '1.75m'; +person[myDataName] = myDataValue;</pre> + +<p>이제 저장하고 리로드후 아래코드를 입력해보세요.</p> + +<pre class="brush: js">person.height</pre> + +<p>점 표기법으로는 위의 예제처럼 멤버의 이름을 동적으로 사용할 수 없고, 상수 값만을 사용해야 합니다.</p> + +<h2 id="this_는_무엇인가">"this" 는 무엇인가?</h2> + +<p>자, 우리가 이제 보게될 메소드가 좀 이상하게 보일 수도 있을겁니다. 예제를 한번 봐주세요</p> + +<pre class="brush: js">greeting: function() { + alert('Hi! I\'m ' + this.name.first + '.'); +}</pre> + +<p>아마도 "this" 가 뭔지 의아하실 것입니다. <code>this</code> 키워드는 지금 동작하고 있는 코드를 가지고 있는 객체를 가리킵니다. 위의 예제에서 <code>this</code> 는 <code>person</code> 객체와 동일합니다. 그럼 왜 직접 <code>person</code> 객체를 쓰지 않은걸까요? 앞으로 보게될 <a href="/ko/docs/Learn/JavaScript/Objects/Object-oriented_JS">입문자를 위한 객체 지향 JavaScript</a> 문서에서 우리가 생성자를 공부하게 될 때, 혹은 그것 말고도 기타 등등의 상황에서 <code>this</code> 는 매우 유용하게 사용됩니다. 이 this 라는 녀석은 객체 멤버의 컨텍스트가 바뀌는 경우에도 언제나 정확한 값을 사용하게 해줍니다(예를 들어, 두개의 다른 <code>person</code> 객체가 각각 다른 이름으로 인스턴스로 생성된 상태에서 인사말을 출력하기 위해 객체의 name 을 참조해야 한다고 생각해보세요).</p> + +<p>간략화된 person 객체를 가지고 설명을 좀 해보겠습니다.</p> + +<pre class="brush: js">var person1 = { + name: 'Chris', + greeting: function() { + alert('Hi! I\'m ' + this.name + '.'); + } +} + +var person2 = { + name: 'Brian', + greeting: function() { + alert('Hi! I\'m ' + this.name + '.'); + } +}</pre> + +<p>이 예제에서, 메소드의 실제 코드는 완전히 동일하지만 <code>person1.greeting()</code> 은 "Hi! I'm Chris." 를 출력합니다. 반면 <code>person2.greeting()</code> 은 "Hi! I'm Brian." 을 출력하게 됩니다. 앞서 이야기한 것처럼, <code>this</code> 은 실행중인 코드가 속해있는 객체입니다. 객체 리터럴을 직접 지정해서 사용하는 경우라면 그리 유용하지 않겠지만, 동적으로 객체를 생성하는 경우(예를 들면 생성자를 사용하는 경우)에는 매우 유용합니다. 이 부분은 추후에 더 명확하게 이해가 될 겁니다.</p> + +<h2 id="객체를_줄곧_사용해_왔습니다">객체를 줄곧 사용해 왔습니다</h2> + +<p>예제코드를 따라하다보니, 이쯤 되면 슬슬 "점" 표기법을 사용하는 것이 꽤 자연스럽게 느껴질 것입니다. 물론 이 코스 내내 사용했기 때문입니다! 샘플에서 사용하였던 브라우저 내장 API 나 JavaScript 객체들은 실제로 우리가 공부했던 구조와 완전히 동일한 방법으로 구현된 것들입니다. 물론 우리가 봤던 예제보다 복잡하기는 합니다.</p> + +<p>자, 다음과 같이 String의 메소드를 사용했다고 가정합시다.</p> + +<pre class="brush: js">myString.split(',');</pre> + +<p><code><a href="https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/String">String</a></code> 클래스의 인스턴스가 가진 메소드를 사용하고 있습니다. 코드에서 String 을 생성할 때 마다 <code>String</code> 의 인스턴스가 만들어지고, 그렇게 만들어진 인스턴스는 당연히 공통적으로 사용할 수 있는 메소드와 프러퍼티를 가집니다.</p> + +<p>아래와 같이 도큐먼트 오브젝트 모델(DOM)에 접근할때면,</p> + +<pre class="brush: js">var myDiv = document.createElement('div'); +var myVideo = document.querySelector('video');</pre> + +<p><code><a href="https://developer.mozilla.org/ko/docs/Web/API/Document">Document</a></code> 클래스의 인스턴스를 통해 메소드를 사용하고 있는 것입니다. 각 웹페이지가 로딩될 때, <code>Document</code> 인스턴스가 만들어지고, 전체 웹 페이지 구조와 컨텐츠 그리고 URL같은 기능들을 제공하는 <code>document</code> 가 호출됩니다. 다시 말하지만 이건 여러 공통 메소드와 프로퍼티들이 이 인스턴스를 통해 사용가능하게 됩니다.</p> + +<p>우리가 계속 사용해왔던 다른 내장 객체/API(<code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Array">Array</a></code>, <code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Math">Math</a></code> 등등)들도 마찬가지입니다</p> + +<p>모든 내장 객체/API가 자동으로 객체의 인스턴스를 생성하는 것은 아니라는 것에 주의 하세요. 예를 들어, <a href="/ko/docs/Web/API/Notifications_API">Notifications API</a> — 최근 브라우져들이 시스템 알림을 사용하게 하는 기능 — 는 사용자가 발생시시길 원하는 notification 만을 선택하게 하는 생성자를 사용해야 합니다. JavaScript 콘솔에 다음 내용을 입력해보세요</p> + +<pre class="brush: js">var myNotification = new Notification('Hello!');</pre> + +<p>다음 문서에서 생성자에 대해서 좀더 자세히 알아볼 것입니다.</p> + +<div class="note"> +<p><strong>Note</strong>: 객체간 통신은 <strong>message passing</strong> 방식을 사용한다고 생각하는게 좋습니다. 한 객체가 다른 객체에게 어떤 액션을 요청해야 하는 경우, 그 객체는 다른 객체가 가지고 있는 메소드를 통해서 메세지를 보내는 것이고, 응답을 기다리는 것입니다. 그 응답은 것이 우리가 알고 있는 return 값입니다.</p> +</div> + +<h2 id="요약">요약</h2> + +<p>축하합니다, 첫 번째 JavaScript 객체 설명 문서를 끝까지 읽으셨습니다. 이제 여러분은 JavaScript 객체를 어떻게 활용하는지 이해하게 되었습니다. 간단한 사용자 정의 객체를 만드는 방법을 포함해서요. 또 객체는 데이터와 연관된 함수를 저장하는데 매우 유용한 구조라는 것도 알게 되었습니다. 만약 <code>person</code> 객체가 가지고 있는 모든 프로퍼티와 메소드를 따로 따로 분리된 변수와 함수로 구현하려고 한다면 그것이야 말로 비효율적이고 끔찍한 일이 될 것입니다. 변수명과 함수명들이 중복된다거나 하는 일도 비일비재 할 것입니다. 객체는 고유의 패키지에 우리의 정보를 안전하게 정보를 보호해주는 역활을 합니다.</p> + +<p>다음 장에서는 객체지향(OOP) 이론을 배우고, JavaScript 에서는 객체지향이 어떻게 사용되었는지 알아볼 것입니다.</p> + +<p>{{NextMenu("Learn/JavaScript/Objects/Object-oriented_JS", "Learn/JavaScript/Objects")}}</p> + +<h2 id="이_모듈_에서는">이 모듈 에서는</h2> + +<ul> + <li><a href="https://developer.mozilla.org/ko/docs/Learn/JavaScript/Objects/Basics">객체 기본</a></li> + <li><a href="https://developer.mozilla.org/ko/docs/Learn/JavaScript/Objects/Object-oriented_JS">입문자를위한 객체 지향 JavaScript</a></li> + <li><a href="https://developer.mozilla.org/ko/docs/Learn/JavaScript/Objects/Object_prototypes">객체 프로토타입</a></li> + <li><a href="https://developer.mozilla.org/ko/docs/Learn/JavaScript/Objects/Inheritance">JavaScript 에서의 상속</a></li> + <li><a href="https://developer.mozilla.org/ko/docs/Learn/JavaScript/Objects/JSON">JSON 데이터와 작업</a></li> + <li><a href="https://developer.mozilla.org/ko/docs/Learn/JavaScript/Objects/Object_building_practice">객체 생성 실습</a></li> + <li><a href="https://developer.mozilla.org/ko/docs/Learn/JavaScript/Objects/Adding_bouncing_balls_features">bouncing balls demo 에 기능들 추가하기</a></li> +</ul> diff --git a/files/ko/learn/javascript/objects/index.html b/files/ko/learn/javascript/objects/index.html new file mode 100644 index 0000000000..9bdd5d8a66 --- /dev/null +++ b/files/ko/learn/javascript/objects/index.html @@ -0,0 +1,50 @@ +--- +title: JavaScript 객체 소개 +slug: Learn/JavaScript/Objects +tags: + - 객체 + - 배우기 + - 입문자 + - 자바스크립트 + - 지침 + - 코딩스크립트 + - 평가 +translation_of: Learn/JavaScript/Objects +--- +<div>{{LearnSidebar}}</div> + +<p class="summary"> 자바스크립트에서는 스트링과 배열과같은 기본적인 기능부터 가장 상단에 놓여진 브라우저 API에 이르기까지 대부분의 것들이 객체입니다. 사용자는 관련된 함수들과 변수들을 효율적인 패키지로 추상화하거나 편리한 데이터 컨테이너로 작동하는 객체를 만들 수 있습니다. 언어에 대한 지식을 가지고 더 멀리 나아고자 한다면 자바스크립트의 객체 기반의 본질을 이해하는 것이 중요하므로, 여러분을 돕기위해 이 모듈을 제공하였습니다. 여기에서는 객체 이론과 구문을 자세히 가르쳐드리며, 사용자 정의 객체를 만드는 방법도 알아볼 것입니다.</p> + +<h2 id="사전_지식">사전 지식</h2> + +<p>이 장을 읽기 전에, 여러분은 HTML 과 CSS 를 어느 정도 알고 있어야 합니다. 그렇지 않다면 <a href="/ko/docs/Web/Guide/HTML/Introduction">HTML 소개</a>와 <a href="/ko/docs/Learn/CSS/Introduction_to_CSS">CSS 소개</a>를 먼저 읽고 오시기 바랍니다.</p> + +<p>JavaScript 객체에 대해 자세히 알아보려면, 기본 문법에 대해 어느 정도 능숙해야 합니다. 이 장을 읽기 전에 <a href="/ko/docs/Learn/JavaScript/First_steps">JavaScript 첫걸음</a>과 <a href="/ko/docs/Learn/JavaScript/Building_blocks">JavaScript 구성 요소</a>를 먼저 읽어보시기를 바랍니다.</p> + +<div class="note"> +<p><strong>Note</strong>: 컴퓨터/태블릿/혹은 다른 디바이스 상에서 스스로 파일을 만들수 없는 환경이라면, <a href="http://jsbin.com/">JSBin</a> 또는 <a href="https://thimble.mozilla.org/">Thimble</a> 과 같은 온라인 코딩 프로그램을 이용하여 (거의 모든) 예제 코드를 테스트해 보실 수 있습니다.</p> +</div> + +<h2 id="가이드">가이드</h2> + +<dl> + <dt><a href="/ko/docs/Learn/JavaScript/Objects/Basics">객체 기본</a></dt> + <dd>JavaScript 객체 소개의 첫 장에서는, 기본적인 JavaScript 객체 문법을 볼 것이며, 이전 과정에서 이미 봐왔던 몇몇 JavaScript 특징들을 다시 들여다 볼 것입니다. 이를 통해 우리는 이전에 다루었던 많은 특징들이 사실상 객체였다는 사실을 알게 될 것입니다.</dd> + <dt><a href="/ko/docs/Learn/JavaScript/Objects/Object-oriented_JS">입문자를 위한 객체지향 자바스크립트</a></dt> + <dd>가장 기본적인 것으로, 우리는 객체 지향 JavaScript(OOJS) 에 초점을 둘 것입니다. 이 글에서는 객체 지향 프로그래밍(OOP) 이론의 기본 관점을 보여주고, JavaScript 가 생성자함수를 이용하여 객체 클래스를 에뮬레이트 하는 방법과 객체 인스턴스를 생성하는 방법에 대해 탐구합니다.</dd> + <dt><a href="/ko/docs/Learn/JavaScript/Objects/Object_prototypes">객체 프로토타입</a></dt> + <dd>프로토타입은 JavaScript 객체가 또다른 객체로 특성을 상속시키기 위한 메커니즘이고, 그것들은 고전적인 객체 지향 프로그래밍 언어들의 상속 메커니즘과 다르게 작동합니다. 이 글에서는 그 다름을 탐구하고, 프로토타입 체인이 동작하는 방식을 설명하며 프로토타입의 속성이 기본 생성자들로 메소드를 추가하기 위해 사용되는 방법을 보여줍니다.</dd> + <dt><a href="/ko/docs/Learn/JavaScript/Objects/Inheritance">자바스크립트에서의 상속</a></dt> + <dd>이제 OOJS 에 대한 대부분의 세부사항들에 대해서 설명이 되었으므로, 본 장에서는 "부모" 클래스로부터 특성을 상속받은 "자식" 오브젝트 클래스를 생성하는 방법을 보여줍니다. 뿐만 아니라, OOJS 를 언제 또는 어디서 사용하면 좋을 지에 대한 몇몇 조언도 기술되어있습니다.</dd> + <dt><a href="/ko/docs/Learn/JavaScript/Objects/JSON">JSON 데이터와 작업</a></dt> + <dd>JSON(JavaScript Object Notation) 은 JavaScript 객체 문법상의 구조화된 데이터를 표현하기 위한 표준 텍스트기반 포맷입니다. 그래서 주로 웹사이트 상에 데이터를 표현하고 전송하는 데 사용되고 있습니다(예를 들면, 웹페이지 상에 데이터를 디스플레이할 수 있도록 서버에서 클라이언트로의 데이터 전송). 이 글에서는 데이터에 접근하기 위해 JSON 을 파싱하고, 또 자신만의 JSON 을 작성하는 것처럼 자바스크립트를 사용하여 JSON 과 연동할 필요가 있는 모든 것들을 보여드릴 것입니다.</dd> + <dt><a href="/ko/docs/Learn/JavaScript/Objects/Object_building_practice">객체 생성 실습</a></dt> + <dd>이전 글들에서 우리는 JavaScript 객체 이론과 문법 세부사항의 중요한 것들을 보았습니다. 본 장에서는 커스텀 JavaScript 객체를 생성하는 다양한 연습을 하면서 실용적인 예들을 깊이 다룹니다.</dd> +</dl> + +<h2 id="평가">평가</h2> + +<dl> + <dt><a href="/en-US/docs/Learn/JavaScript/Objects/Adding_bouncing_balls_features">Bouncing balls demo 에 기능들 추가</a></dt> + <dd>이 평가에서는 여러분이 이전 글의 bouncing balls demo 를 시작점으로 하여, 몇 가지 새롭고 재미있는 기능들을 추가하길 기대합니다.</dd> +</dl> diff --git a/files/ko/learn/javascript/objects/inheritance/index.html b/files/ko/learn/javascript/objects/inheritance/index.html new file mode 100644 index 0000000000..72a2302d15 --- /dev/null +++ b/files/ko/learn/javascript/objects/inheritance/index.html @@ -0,0 +1,394 @@ +--- +title: Inheritance in JavaScript +slug: Learn/JavaScript/Objects/Inheritance +translation_of: Learn/JavaScript/Objects/Inheritance +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Objects/Object_prototypes", "Learn/JavaScript/Objects/JSON", "Learn/JavaScript/Objects")}}</div> + +<p class="summary">OOJS에 대한 온갖 잡지식을 설명했으니, 이 글에서는 부모 클래스에서 자식 클래스를 상속하는 방법을 알아봅니다. 덤으로 OOJS를 구현하는데 몇 가지 참고사항도 있습니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">선수조건:</th> + <td>컴퓨터 기본지식, HTML과 CSS에 대한 기본적인 이해,자바스크립트에 어느 정도 익숙할 것 (see <a href="/ko/docs/Learn/JavaScript/First_steps">First steps</a> and <a href="/ko/docs/Learn/JavaScript/Building_blocks">Building blocks</a>). OOJS 기초 지식 (see <a href="/ko/docs/Learn/JavaScript/Objects/Basics">Introduction to objects</a>).</td> + </tr> + <tr> + <th scope="row">학습목표:</th> + <td>Javascript에서 상속을 구현하는 법을 이해합니다.</td> + </tr> + </tbody> +</table> + +<h2 id="프로토타입_상속">프로토타입 상속</h2> + +<p>지금까지 몇 가지 상속을 살펴보았습니다 — 프로토타입 체인이 어떻게 동작하는지, 체인을 통해 멤버들을 탐색하는 것도 보았죠. 하지만 이는 대부분 브라우저가 알아서 처리하는 로직이었습니다. 그러면 우리가 직접 객체를 생성하고 상속하려면 어떻게 해야 할까요?</p> + +<p>실질적인 예제를 통해 알아보도록 합시다.</p> + +<h2 id="시작하기">시작하기</h2> + +<p>먼저 <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/advanced/oojs-class-inheritance-start.html">oojs-class-inheritance-start.html</a>를 다운 받으시고 (<a href="http://mdn.github.io/learning-area/javascript/oojs/advanced/oojs-class-inheritance-start.html">running live</a> 페이지도 보시구요). 파일 내에서 이전 예제에서 계속 봐 왔던 <code>Person()</code> 생성자를 보실 수 있습니다 — 생성자에 속성 몇 개를 정의했기에 조금 다릅니다:</p> + +<pre class="brush: js">function Person(first, last, age, gender, interests) { + this.name = { + first, + last + }; + this.age = age; + this.gender = gender; + this.interests = interests; +};</pre> + +<p>메소드는 <em>전부</em> 아래처럼 prototype에 정의되어 있습니다:</p> + +<pre class="brush: js">Person.prototype.greeting = function() { + alert('Hi! I\'m ' + this.name.first + '.'); +};</pre> + +<div class="note"> +<p><strong>Note</strong>: 소스 코드에는 <code>bio()와</code> <code>farewell()</code>메소드가 정의되어 있습니다. 잠시 후에 다른 생성자로 어떻게 상속하는지 알아보도록 합시다.</p> +</div> + +<p>객체 지향에 대해 처음 정의할 때 언급했었던 <code>Teacher</code> 클래스를 만들어 봅시다. <code>Person</code>을 상속받고 아래 몇 가지를 추가해서요:</p> + +<ol> + <li><code>subject</code> 속성 — 교사가 가르치는 과목을 나타냅니다.</li> + <li>기존의 <code>greeting()</code> 보다 조금 더 공손한 인사를 하는 메소드 — 교사가 학생들에게 건넬 만한 표현으로 하죠.</li> +</ol> + +<h2 id="Teacher()_생성자_함수_정의">Teacher() 생성자 함수 정의</h2> + +<p>제일 처음 단계에서는 <code>Teacher()</code> 생성자를 만들어야 합니다 — 기존 코드 밑에 아래 코드를 추가하세요:</p> + +<pre class="brush: js">function Teacher(first, last, age, gender, interests, subject) { + Person.call(this, first, last, age, gender, interests); + + this.subject = subject; +}</pre> + +<p>Person() 생성자와 여러모로 비슷해 보이지만 여지껏 보지 못했던 한가지 차이점이 있습니다 — <code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Function/call">call()</a></code> 함수죠. call() 함수의 첫번째 매개변수는 다른 곳에서 정의된 함수를 현재 컨텍스트에서 실행할 수 있도록 합니다. 실행하고자 하는 함수의 첫 번째 매개변수로 this를 전달하고 나머지는 실제 함수 실행에 필요한 인자들을 전달하면 됩니다.</p> + +<p>Teacher()의 생성자는 <code>Person()</code>을 상속받았으므로 같은 매개변수들이 필요합니다. 따라서 동일한 매개변수들을 <code>call()</code>의 인자로 전달하여 실행합니다.</p> + +<p>마지막 줄에서는 새 속성인 <code>subject</code>를 정의하여 Person이 아닌 Teacher만이 갖는 속성을 만들어 줍니다.</p> + +<p>참고로 아래와 같이 할 수도 있습니다:</p> + +<pre class="brush: js">function Teacher(first, last, age, gender, interests, subject) { + this.name = { + first, + last + }; + this.age = age; + this.gender = gender; + this.interests = interests; + this.subject = subject; +}</pre> + +<p>다만 이는 <code>Person()</code>을 상속받은게 아니라 단지 동일한 인자를 정의했을 뿐이죠. 이건 원하는 방법이 아닐 뿐더러 코드의 길이만 더 늘어났습니다.</p> + +<h3 id="매개변수가_없는_생성자_상속하기">매개변수가 없는 생성자 상속하기</h3> + +<p>상속하려는 생성자가 속성을 매개변수로 받지 않는다면 <code>call()</code>의 매개변수에도 아무것도 전달할 필요가 없습니다. 아래처럼 간단한 생성자가 있다면:</p> + +<pre class="brush: js">function Brick() { + this.width = 10; + this.height = 20; +}</pre> + +<p><code>width</code>와 <code>height</code> 속성을 상속받기 위해 아래처럼만 하면 됩니다(물론 이후 설명할 방법을 써도 되구요):</p> + +<pre class="brush: js">function BlueGlassBrick() { + Brick.call(this); + + this.opacity = 0.5; + this.color = 'blue'; +}</pre> + +<p><code>call() </code>함수에 this만 넘긴 것을 보세요. — <code>Brick()</code> 생성자에서 매개변수를 통해 초기화 하는 속성들이 없으므로 <code>call()</code>에도 넘길 필요가 없습니다.</p> + +<h2 id="Teacher()의_프로토타입과_생성자_참조_설정하기">Teacher()의 프로토타입과 생성자 참조 설정하기</h2> + +<p>다 좋은데 문제가 있습니다. 방금 정의한 새 생성자에는 생성자 함수 자신에 대한 참조만 가지고 있는 프로토타입 속성이 할당되어 있습니다. 정작 상속 받은 Person() 생성자의 prototype 속성은 없죠. Javascript 콘솔에서 <code>Object.getOwnPropertyNames(Teacher.prototype)</code>을 쳐서 확인해 보세요. 다음엔 <code>Teacher</code>를 <code>Person</code>으로 바꿔서 확인해 보세요. Teacher()생성자는 Person()의 메소드를 상속받지 못하였습니다. <code>Person.prototype.greeting</code>과 <code>Teacher.prototype.greeting</code> 구문을 실행하여 비교해 보세요. <code>Teacher()</code>가 메소드도 상속 받으려면 어떻게 해야 할까요?</p> + +<ol> + <li>기존 코드에 아래 코드를 추가하세요: + <pre class="brush: js">Teacher.prototype = Object.create(Person.prototype);</pre> + 구원 투수 <code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/create">create()</a></code>의 등판입니다. 새 객체를 생성하여 <code>Teacher.prototype</code>으로 할당했죠. 새 객체는 <code>Person.prototype</code> 객체를 자신의 프로토타입으로 가지고 있으므로 <code>Person.prototype</code>에 정의된 모든 메소드를 사용할 수 있습니다.</li> + <li>넘어가기 전에 한가지 더 해야 합니다. 마지막 줄을 추가하고 나면 <code>Teacher.prototype</code>의 <code>constructor</code> 속성이 Person()으로 되어 있습니다. <code>Teacher.prototype</code>에 <code>Person.prototype</code>을 상속받은 객체를 할당했기 때문이죠. 코드를 저장한 뒤 브라우저로 불러와서 Teacher.prototype.constructor 구문의 반환 값을 확인해 보세요.</li> + <li>문제의 소지가 있으므로 고쳐야 됩니다. 소스에 아래 코드를 추가하세요: + <pre class="brush: js">Teacher.prototype.constructor = Teacher;</pre> + </li> + <li>저장하고 다시 브라우저에서 불러오면 의도한대로 <code>Teacher.prototype.constructor</code>가 <code>Teacher()</code>를 반환합니다. 게다가 <code>Person()</code>도 상속받았죠!</li> +</ol> + +<h2 id="Teacher()에_새_greeting()_함수_부여하기">Teacher()에 새 greeting() 함수 부여하기</h2> + +<p><code>Teacher()</code>에 새로운 <code>greeting()</code> 함수를 정의하여 코드를 완성합시다.</p> + +<p>가장 간단한 방법은 Teacher()의 프로토타입에 정의합니다. — 아래 코드를 추가하세요:</p> + +<pre class="brush: js">Teacher.prototype.greeting = function() { + var prefix; + + if (this.gender === 'male' || this.gender === 'Male' || this.gender === 'm' || this.gender === 'M') { + prefix = 'Mr.'; + } else if (this.gender === 'female' || this.gender === 'Female' || this.gender === 'f' || this.gender === 'F') { + prefix = 'Mrs.'; + } else { + prefix = 'Mx.'; + } + + alert('Hello. My name is ' + prefix + ' ' + this.name.last + ', and I teach ' + this.subject + '.'); +};</pre> + +<p>조건문을 이용해서 성별에 따라 적절한 호칭이 붙은 교사의 인삿말을 alert 창으로 띄웁니다.</p> + +<h2 id="예제_사용해_보기">예제 사용해 보기</h2> + +<p>소스를 환성했으니 아래 코드를 통해 새 <code>Teacher()</code> 인스턴스를 생성해 봅시다(아니면 인자를 원하는 값으로 변경하시거나요):</p> + +<pre class="brush: js">var teacher1 = new Teacher('Dave', 'Griffiths', 31, 'male', ['football', 'cookery'], 'mathematics');</pre> + +<p>저장한 코드를 다시 불러와서 아래처럼 <code>teacher1</code>의 속성과 메소드를 확인해 봅시다:</p> + +<pre class="brush: js">teacher1.name.first; +teacher1.interests[0]; +teacher1.bio(); +teacher1.subject; +teacher1.greeting(); +teacher1.farewell();</pre> + +<p>아주 잘 실행될 겁니다. 1, 2, 3, 6 줄은 Person() 생성자(클래스)에서 상속 받은 멤버에 접근합니다. 4번째 줄은 Teacher() 생성자(클래스)만 가지고 있는 멤버에 접근합니다. 5번째 줄은 Person()에서 상속 받은 멤버도 있지만 Teacher()가 이미 자신만의 새 메소드를 정의했으므로 Teacher()의 메소드에 접근합니다.</p> + +<div class="note"> +<p><strong>Note</strong>: 코드가 잘 동작하지 않으면 <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/advanced/oojs-class-inheritance-finished.html">완성된 버전</a>을 확인해 보세요. (<a href="http://mdn.github.io/learning-area/javascript/oojs/advanced/oojs-class-inheritance-finished.html">실행 페이지</a>도 보시구요).</p> +</div> + +<p>이 테크닉이 Javascript에서 상속 받는 클래스를 만드는 유일한 방법은 아니지만 잘 동작하며 상속을 구현하는 방법을 잘 설명하고 있습니다.</p> + +<p>조금 더 명확한 방식으로 Javascript에서 상속을 구현하는 새 {{glossary("ECMAScript")}} 기능도 관심 가질만한 주제입니다(<a href="/ko/docs/Web/JavaScript/Reference/Classes">Classes</a> 참조). 아직까지 많은 브라우저에서 지원하지 못하고 있기 때문에 여기서 다를 주제는 아닙니다. 여러 문서에서 제시한 코드들은 IE9보다 더 오래된 구형 브라우저에서도 사용 가능하며 더 이전 버전을 지원하기 위한 방법들도 있습니다. </p> + +<p>JavaScript 라이브러리를 쓰면 간단합니다 — 상속 기능을 사용하기 위한 보편적인 방법이죠. 예를들어 <a href="http://coffeescript.org/#classes">CoffeeScript</a>는 <code>class</code>와 <code>extends</code>등의 기능을 제공합니다.</p> + +<h2 id="더_연습하기">더 연습하기</h2> + +<p><a href="/ko/docs/Learn/JavaScript/Objects/Object-oriented_JS#Object-oriented_programming_from_10000_meters">OOP theory section</a>, 에서는 개념적으로 Person을 상속받고 Teacher보다 덜 공손한 <code>greeting()</code> 메소드를 재정의한 <code>Student</code> 클래스를 정의했었습니다. 해당 절에서 <code>Student</code>의 인삿말이 어땠는지 확인해 보시고 <code>Person()</code>을 상속받는 <code>Student()</code> 생성자를 구현해 보세요. <code>greeting()</code> 함수도 재정의 해 보시구요.</p> + +<div class="note"> +<p><strong>Note</strong>: 코드가 잘 동작하지 않으면 <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/advanced/oojs-class-inheritance-student.html">완성된 버전</a> 을 확인해 보세요.(<a href="http://mdn.github.io/learning-area/javascript/oojs/advanced/oojs-class-inheritance-student.html">실행 페이지</a>도 보시구요).</p> +</div> + +<h2 id="객체_멤버_요약">객체 멤버 요약</h2> + +<p>요약하면, 상속에 있어 고려해야 할 세 가지 유형의 속성/메소드가 있습니다:</p> + +<ol> + <li>생성자 함수 내에서 인스턴스에 정의하는 유형. 직접 작성한 코드에서는 생성자 함수 내에 <code>this.x = x</code> 구문과 유사하게 정의되어 있으므로 발견하기 쉽습니다. 브라우저 내장 코드에서는 객체 인스턴스(보통 <code>new</code> 키워드를 통해 생성, ex) <code>var myInstance = new myConstructor()</code>)에서만 접근할 수 있는 멤버입니다.</li> + <li>생성자에 직접 정의하는 유형, 생성자에서만 사용 가능합니다. 브라우저 내장 객체에서 흔히 사용하는 방식인데, 인스턴스가 아니라 생성자 함수에서 바로 호출되는 유형입니다. <code>Object.key()</code> 같은 함수들이죠.</li> + <li>인스턴스와 자식 클래스에 상속하기 위해 생성자의 프로토타입에 정의하는 유형. 생성자의 프로토타이비 속성에 정의되는 모든 멤버를 의미합니다. ex) <code>myConstructor.prototype.x()</code>.</li> +</ol> + +<p>뭐가 뭔지 헷갈려도 걱정하지 마세요 — 배우는 중이니 차츰 익숙해질겁니다.</p> + +<h2 id="ECMAScript_2015_클래스">ECMAScript 2015 클래스</h2> + +<p>ECMAScript 2015에서는 C++나 Java와 유사한 <a href="/ko/docs/Web/JavaScript/Reference/Classes">클래스 문법</a>을 공개하여 클래스를 조금 더 쉽고 명확하게 재활용 할 수 있게 되었습니다. 이 절에서는 프로토타입 상속으로 작성한 Person과 Teacher 예제를 클래스 문법으로 변경하고 어떻게 동작하는지 설명하겠습니다.</p> + +<div class="note"> +<p><strong>Note</strong>: 대부분의 최신 브라우저에서 새로운 클래스 작성 방식을 지원합니다만 일부 구형 브라우저(Internet Explorer가 대표적)에서는 동작하지 않으므로 하위호환성을 위해 프로토타입 상속을 배워둘 필요가 있습니다.</p> +</div> + +<p>Class-스타일로 재작성한 Person 예제를 보시죠:</p> + +<pre><code>class Person { + constructor(first, last, age, gender, interests) { + this.name = { + first, + last + }; + this.age = age; + this.gender = gender; + this.interests = interests; + } + + greeting() { + console.log(`Hi! I'm ${this.name.first}`); + }; + + farewell() { + console.log(`${this.name.first} has left the building. Bye for now!`); + }; +}</code></pre> + +<p><a href="/ko/docs/Web/JavaScript/Reference/Statements/class">class</a> 구문은 새로운 클래스를 작성함을 의미합니다. Class 블록 내에서 모든 기능을 정의할 수 있습니다.</p> + + + +<ul> + <li><code><a href="/ko/docs/Web/JavaScript/Reference/Classes/constructor">constructor()</a></code> 메소드는 <code>Person</code> 클래스의 생성자를 의미합니다.</li> + <li><code>greeting()</code> and <code>farewell()</code>는 멤버 메소드입니다. 클래스의 메소드는 생성자 다음에 아무 메소드나 추가할 수 있습니다. 여기서는 읽기 쉬우라고 string 결합이 아닌 <a href="/ko/docs/Web/JavaScript/Reference/Template_literals">template literals</a>을 사용했습니다.</li> +</ul> + +<p>이제 위에서 했듯이 <a href="/ko/docs/Web/JavaScript/Reference/Operators/new"><code>new</code> 연산자</a>로 객체 인스턴스를 생성할 수 있습니다:</p> + +<pre><code>let han = new Person('Han', 'Solo', 25, 'male', ['Smuggling']); +han.greeting(); +// Hi! I'm Han + +let leia = new Person('Leia', 'Organa', 19, 'female' ['Government']); +leia.farewell(); +// Leia has left the building. Bye for now</code></pre> + +<div class="note"> +<p><strong>Note</strong>: 코드를 까보면 class 부분은 프로토타입 상속으로 변환이 됩니다. — 문법 설탕(syntactic sugar)의 일종인거죠. 하지만 읽기 쉽다는데 대부분 동의하실 겁니다.</p> +</div> + +<h3 id="class_문법으로_상속">class 문법으로 상속</h3> + +<p>위에서 사람을 나타내는 클래스를 만들었습니다. Person 클래스는 일반적인 사람이 가질 만한 특성들을 나열하고 있죠; 이 절에서는 <code>Person</code>을 class 문법으로 상속받아 <code>Teacher</code> 클래스를 만들 예정입니다. 이 작업을 하위 클래스 생성이라 부릅니다.</p> + +<p>하위 클래스를 만드려면 Javascript에서 <a href="/ko/docs/Web/JavaScript/Reference/Classes/extends">extends 키워드</a>를 통해 상속 받을 클래스를 명시합니다.</p> + +<pre><code>class Teacher extends Person { + constructor(first, last, age, gender, interests, subject, grade) { + this.name = { + first, + last + }; + + this.age = age; + this.gender = gender; + this.interests = interests; + // subject and grade are specific to Teacher + this.subject = subject; + this.grade = grade; + } +}</code></pre> + +<p><code>constructor()</code>에서 첫번쨰로 <a href="/ko/docs/Web/JavaScript/Reference/Operators/super"><code>super()</code> 연산자</a>를 정의하면 코드를 조금 더 읽기 쉬워집니다. 이는 상위 클래스의 생성자를 호출하며 super()의 매개변수를 통해 상위 클래스의 멤버를 상속받을 수 있는 코드입니다.</p> + +<pre><code>class Teacher extends Person { + constructor(first, last, age, gender, interests, subject, grade) { + super(first, last, age, gender, interests); + + // subject and grade are specific to Teacher + this.subject = subject; + this.grade = grade; + } +}</code></pre> + +<p><code>Teacher</code>의 인스턴스를 생성하면 의도한대로 이제 <code>Teacher</code>와 <code>Person</code> 양 쪽의 메소드와 속성을 사용할 수 있습니다.</p> + +<pre><code>let snape = new Teacher('Severus', 'Snape', 58, 'male', ['Potions'], 'Dark arts', 5); +snape.greeting(); // Hi! I'm Severus. +snape.farewell(); // Severus has left the building. Bye for now. +snape.age // 58 +snape.subject; // Dark arts</code></pre> + +<p>Person을 수정하지 않고 Teacher를 생성한 것처럼 또 다른 하위클래스도 생성할 수 있습니다.</p> + +<div class="note"> +<p><strong>Note</strong>: GitHub에서 <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/advanced/es2015-class-inheritance.html">es2015-class-inheritance.html</a> 예제를 참조하세요(<a href="https://mdn.github.io/learning-area/javascript/oojs/advanced/es2015-class-inheritance.html">실행 페이지</a>).</p> +</div> + +<h2 id="Getters와_Setters">Getters와 Setters</h2> + +<p>생성한 클래스 인스턴스의 속성 값을 변경하거나 최종 값을 예측할 수 없는 경우가 있을 겁니다. Teacher 예제를 보면 인스턴스를 생성하기 전에는 어떤 과목을 가르칠지 아직 모릅니다. 학기 도중에 가르치는 과목이 변경될 수도 있구요.</p> + +<p>이런 상황에 getter/setter가 필요합니다.</p> + +<p>Teacher 클래스에 getter/setter를 추가해 봅시다. 마지막에 작성했던 예제를 그대로 사용해보죠.</p> + +<p>Getter와 setter는 쌍으로 동작합니다. Getter가 현재 값을 반환한다면 그에 대응하는 setter는 해당하는 값을 변경합니다.</p> + +<p>수정된 <code>Teacher</code> 클래스는 아래와 같습니다:</p> + +<pre><code>class Teacher extends Person { + constructor(first, last, age, gender, interests, subject, grade) { + super(first, last, age, gender, interests); + // subject and grade are specific to Teacher + this._subject = subject; + this.grade = grade; + } + + get subject() { + return this._subject; + } + + set subject(newSubject) { + this._subject = newSubject; + } +}</code></pre> + +<p>위 클래스를 보시면 <code>subject</code> 속성에 대해 getter와 setter가 생겼습니다. 멤버 변수에는 _를 붙여 getter/setter와 구분을 하였습니다. 이렇게 하지 않으면 get/set을 호출할때마다 에러가 발생합니다:</p> + +<ul> + <li><code>snape</code> 객체의 <code>_subject</code> 속성 값을 보려면 <code>snape._subject</code>를 실행합니다.</li> + <li>To show the current value of the <code>_subject</code> property of the <code>snape</code> object we can use <code>snape._subject</code>.</li> + <li><code>_subject</code>에 새 값을 할당하려면 <code>snape._subject="new value"</code>를 실행합니다.</li> +</ul> + +<p>두 기능이 실제로 어떻게 작동하는지 아래를 참조하세요:</p> + +<pre><code>// Check the default value +console.log(snape._subject) // Returns "Dark arts" + +// Change the value +snape._subject="Balloon animals" // Sets subject to "Balloon animals" + +// Check it again and see if it matches the new value +console.log(snape._subject) // Returns "Balloon animals"</code></pre> + +<div class="note"> +<p><strong>Note</strong>: GitHub에서 <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/advanced/es2015-getters-setters.html">es2015-getters-setters.html</a> 예제를 참조하세요(<a href="https://mdn.github.io/learning-area/javascript/oojs/advanced/es2015-getters-setters.html">실행 페이지</a>).</p> +</div> + +<h2 id="JavaScript에서_언제_상속을_사용해야_할까">JavaScript에서 언제 상속을 사용해야 할까?</h2> + +<p>이 마지막 문서를 읽고 나면 "뭐가 이리 어렵냐"고 생각하실지도 모르겠습니다. 어렵긴 합니다 프로토타입과 상속은 Javascript에서 가장 난해한 부분이거든요. 하지만 이 부분은 Javascript가 강력하고 유연한 언어로써 작용할 수 있는 원동력이기에 충분한 시간을 들여 배울 가치가 있습니다.</p> + +<p>어찌보면 여러분은 항상 상속하고 있었습니다. Web API나 브라우저 내장 객체인 string, array 등의 메소드/속성을 사용하면서 암묵적으로 상속을 사용하고 있었던거죠.</p> + +<p>처음 시작하거나 작은 프로젝트에서 직접 상속을 구현하는 코드를 작성하는 경우는 그리 많지 않습니다. 필요하지도 않는데 상속을 위한 코드를 구현하는 건 시간 낭비에 불과하죠. 하지만 코드량이 많아질수록 상속이 필요한 경우가 생깁니다. 동일한 기능을 가진 클래스가 많아졌음을 발견했다면 기능들을 한데 묶어 공유할 수 있도록 일반 객체를 만들고 특이 객체들에게 상속하는 방식이 훨씬 편하고 유용하다는 점을 알 수 있습니다.</p> + +<div class="note"> +<p><strong>Note</strong>: Javascript에서는 프로토타입을 통해 상속이 구현되어 있어 이 방식을 흔히 <strong>위임</strong>이라고 표현합니다. 특이 객체들이 일반 객체에게 일부 기능의 실행을 위임하는 것이죠.</p> +</div> + +<p>상속을 구현할때 상속 레벨을 너무 깊게 하지 말고, 메소드와 속성들이 정확히 어디에 구현되어 있는지 항상 인지해야 합니다. 브라우저 내장 객체의 prototype 역시 일시적으로 수정이 가능하지만 정말로 필요한 경우를 제외하고는 건드리지 말아야 합니다. 너무 깊은 상속은 디버그 할 때 끝없는 혼돈과 고통만을 줄 겁니다.</p> + +<p>궁극적으로 객체는 함수나 반복문과 같이 고유한 역할과 장점을 지닌 채 코드를 재사용하는 또 다른 방법입니다. 서로 연관된 변수와 함수들을 하나로 묶어 다룰 필요가 있을때 객체가 좋은 아이디어입니다. 한 곳에서 다른 곳으로 데이터 집합을 전달할 때에도 객체가 유용합니다. 두가지 모두 생성자나 상속 없이도 가능한 일입니다. 딱 하나의 인스턴스만 필요할 경우 객체를 선언하지 않고 객체 리터럴만으로도 충분합니다. 당연히 상속은 필요없구요.</p> + +<h2 id="요약">요약</h2> + +<p>이 글에서는 여러분들이 반드시 알아야 할 OOJS 이론과 문법의 나머지 부분에 대해 다루고 있습니다. 이 시점에서 여러분은 javascript 객체와 OOP 기초, 프로토타입과 프로토타입 상속, 클래스(생성자)를 만들고 인스턴스를 생성하며 기능을 추가하고, 다른 클래스를 상속 받아 하위 클래스를 만드는 방법을 배웠습니다.</p> + +<p>다음 글에서는 Javascript 객체로 데이터를 교환하는 방식인 Javascript Object Notation(JSON)에 대해 알아봅시다.</p> + +<h2 id="See_also">See also</h2> + +<ul> + <li><a href="http://www.objectplayground.com/">ObjectPlayground.com</a> — A really useful interactive learning site for learning about objects.</li> + <li><a href="https://www.amazon.com/gp/product/193398869X/">Secrets of the JavaScript Ninja</a>, Chapter 6 — A good book on advanced JavaScript concepts and techniques, by John Resig and Bear Bibeault. Chapter 6 covers aspects of prototypes and inheritance really well; you can probably track down a print or online copy fairly easily.</li> + <li><a href="https://github.com/getify/You-Dont-Know-JS/blob/master/this%20&%20object%20prototypes/README.md#you-dont-know-js-this--object-prototypes">You Don't Know JS: this & Object Prototypes</a> — Part of Kyle Simpson's excellent series of JavaScript manuals, Chapter 5 in particular looks at prototypes in much more detail than we do here. We've presented a simplified view in this series of articles aimed at beginners, whereas Kyle goes into great depth and provides a more complex but more accurate picture.</li> +</ul> + +<p>{{PreviousMenuNext("Learn/JavaScript/Objects/Object_prototypes", "Learn/JavaScript/Objects/JSON", "Learn/JavaScript/Objects")}}</p> + + + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Basics">Object basics</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object-oriented_JS">Object-oriented JavaScript for beginners</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object_prototypes">Object prototypes</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Inheritance">Inheritance in JavaScript</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/JSON">Working with JSON data</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object_building_practice">Object building practice</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Adding_bouncing_balls_features">Adding features to our bouncing balls demo</a></li> +</ul> diff --git a/files/ko/learn/javascript/objects/json/index.html b/files/ko/learn/javascript/objects/json/index.html new file mode 100644 index 0000000000..a9d5751319 --- /dev/null +++ b/files/ko/learn/javascript/objects/json/index.html @@ -0,0 +1,351 @@ +--- +title: JSON으로 작업하기 +slug: Learn/JavaScript/Objects/JSON +tags: + - JSON + - JSON 객체 + - JSON 문자열로 변환 + - 입문자 + - 초보자 +translation_of: Learn/JavaScript/Objects/JSON +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Objects/Inheritance", "Learn/JavaScript/Objects/Object_building_practice", "Learn/JavaScript/Objects")}}</div> + +<p class="summary">JavaScript Object Notation (JSON)은 Javascript 객체 문법으로 구조화된 데이터를 표현하기 위한 문자 기반의 표준 포맷입니다. 웹 어플리케이션에서 데이터를 전송할 때 일반적으로 사용합니다(서버에서 클라이언트로 데이터를 전송하여 표현하려거나 반대의 경우). 여기저기서 자주 보았을테니 여기선 JSON을 파싱, 데이터에 접근하고 JSON을 생성하는 등 Javascript로 JSON을 다루는 법에 대해 알아봅시다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">사전지식:</th> + <td>컴퓨터 기초, HTML과 CSS에 대한 기본 지식, Javascript 기초 (<a href="/en-US/docs/Learn/JavaScript/First_steps">First steps</a>과 <a href="/en-US/docs/Learn/JavaScript/Building_blocks">Building blocks</a> 참조), OOJS 기초 (<a href="/en-US/docs/Learn/JavaScript/Object-oriented/Introduction">Introduction to objects</a> 참조).</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>JSON에 담긴 데이터를 이용하는 법과 JSON 객체 생성하는 법에 대해 알아보기.</td> + </tr> + </tbody> +</table> + +<h2 id="아니_대체_JSON이_뭐죠">아니, 대체 JSON이 뭐죠?</h2> + +<p>{{glossary("JSON")}} 는 <a href="https://en.wikipedia.org/wiki/Douglas_Crockford">Douglas Crockford</a>가 널리 퍼뜨린 Javascript 객체 문법을 따르는 문자 기반의 데이터 포맷입니다. JSON이 Javascript 객체 문법과 매우 유사하지만 딱히 Javascript가 아니더라도 JSON을 읽고 쓸 수 있는 기능이 다수의 프로그래밍 환경에서 제공됩니다.</p> + +<p>JSON은 문자열 형태로 존재합니다 — 네트워크를 통해 전송할 때 아주 유용하죠. 데이터에 억세스하기 위해서는 네이티브 JSON 객체로 변환될 필요가 있습니다. 별로 큰 문제는 아닌 것이 Javascript는 <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON">JSON</a> 전역 객체를 통해 문자열과 JSON 객체의 상호변환을 지원합니다.</p> + +<div class="note"> +<p><strong>Note</strong>: 문자열에서 네이티브 객체로 변환하는 것은 파싱(Parsing)이라고 합니다. 네트워크를 통해 전달할 수 있게 객체를 문자열로 변환하는 과정은 문자열화(Stringification)이라고 합니다.</p> +</div> + +<p>개별 JSON 객체를 <code>.json</code> 확장자를 가진 단순 텍스트 파일에 저장할 수 있습니다. {{glossary("MIME 타입")}}은 <code>application/json</code> 입니다.</p> + +<h3 id="JSON_구조">JSON 구조</h3> + +<p>위에서 설명했듯이 JSON은 Javascript 객체 리터럴 문법을 따르는 문자열입니다. JSON 안에는 마찬가지로 Javascript의 기본 데이터 타입인 문자열, 숫자, 배열, 불리언 그리고 다른 객체를 포함할 수 있습니다. 이런 방식으로 여러분은 데이터 계층을 구축할 수 있습니다, 아래 처럼요.</p> + +<pre class="brush: json notranslate">{ + "squadName": "Super hero squad", + "homeTown": "Metro City", + "formed": 2016, + "secretBase": "Super tower", + "active": true, + "members": [ + { + "name": "Molecule Man", + "age": 29, + "secretIdentity": "Dan Jukes", + "powers": [ + "Radiation resistance", + "Turning tiny", + "Radiation blast" + ] + }, + { + "name": "Madame Uppercut", + "age": 39, + "secretIdentity": "Jane Wilson", + "powers": [ + "Million tonne punch", + "Damage resistance", + "Superhuman reflexes" + ] + }, + { + "name": "Eternal Flame", + "age": 1000000, + "secretIdentity": "Unknown", + "powers": [ + "Immortality", + "Heat Immunity", + "Inferno", + "Teleportation", + "Interdimensional travel" + ] + } + ] +}</pre> + +<p>이 객체를 Javascript 프로그램에서 로드하고, 예를 들어 <code>superHeroes</code>라는 이름의 변수에 파싱하면 <a href="/en-US/docs/Learn/JavaScript/Objects/Basics">JavaScript object basics</a> 문서에서 보았던 것처럼 점/브라켓 표현법을 통해 객체 내 데이터에 접근할 수 있게 됩니다. 아래와 같이요:</p> + +<pre class="brush: js notranslate">superHeroes.homeTown +superHeroes['active']</pre> + +<p>하위 계층의 데이터에 접근하려면, 간단하게 프로퍼티 이름과 배열 인덱스의 체인을 통해 접근하면 됩니다. 예를 들어 superHeroes의 두 번째 member의 세 번째 power에 접근하려면 아래와 같이 하면 됩니다.</p> + +<pre class="brush: js notranslate">superHeroes['members'][1]['powers'][2]</pre> + +<ol> + <li>우선 변수 이름은 — <code>superHeroes</code>입니다.</li> + <li><code>members</code> 프로퍼티에 접근하려면, <code>["members"]</code>를 입력합니다.</li> + <li><code>members</code>는 객체로 구성된 배열입니다. 두 번째 객체에 접근할 것이므로 <code>[1]</code>를 입력합니다.</li> + <li>이 객체에서 <code>powers</code> 프로퍼티에 접근하려면 <code>["powers"]</code>를 입력합니다.</li> + <li><code>powers</code> 프로퍼티 안에는 위에서 선택한 hero의 superpower들이 있습니다. 세 번째 것을 선택해야 하므로 <code>[2]</code>.</li> +</ol> + +<div class="note"> +<p><strong>Note</strong>: 위에서 볼 수 있듯 <a href="http://mdn.github.io/learning-area/javascript/oojs/json/JSONTest.html">JSONTest.html</a> 예제에서 JSON 내 변수(<a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/json/JSONTest.html">source code</a> 참고)를 만들었다. 당신 브라우저의 Javascript 콘솔을 통하여 이 코드를 로드하고 그 변수 안에 얻을 수 있는 데이터에 접근해보자.</p> +</div> + +<h3 id="JSON에서의_배열">JSON에서의 배열</h3> + +<p>앞서 JSON 텍스트는 기본적으로 자바스크립트의 오브젝트와 비슷하게 생겼다고 언급하였습니다. 그리고 그것은 대부분 맞습니다. "대부분 맞다"라고 말한 이유는 자바스크립트의 배열 또한 JSON에서 유효하기 때문입니다.</p> + +<pre class="brush: json notranslate">[ + { + "name": "Molecule Man", + "age": 29, + "secretIdentity": "Dan Jukes", + "powers": [ + "Radiation resistance", + "Turning tiny", + "Radiation blast" + ] + }, + { + "name": "Madame Uppercut", + "age": 39, + "secretIdentity": "Jane Wilson", + "powers": [ + "Million tonne punch", + "Damage resistance", + "Superhuman reflexes" + ] + } +]</pre> + +<p>위 예제는 완벽히 올바른 형태의 JSON입니다. 배열의 요소(파싱된 버전)에 접근하기 위해서는 배열의 인덱스를 사용하면 됩니다. <code>[0]["powers"][0]</code> 와 같이 말이죠.</p> + +<h3 id="Other_notes">Other notes</h3> + +<ul> + <li>JSON은 순수히 데이터 포맷입니다. 오직 프로퍼티만 담을 수 있습니다. 메서드는 담을 수 없습니다.</li> + <li>JSON은 문자열과 프로퍼티의 이름 작성시 큰 따옴표만을 사용해야 합니다. 작은 따옴표는 사용불가합니다.</li> + <li>콤마나 콜론을 잘못 배치하는 사소한 실수로 인해 JSON파일이 잘못되어 작동하지 않을 수 있습니다. <a href="http://jsonlint.com/">JSONLint</a>같은 어플리케이션을 사용해 JSON 유효성 검사를 할 수 있습니다.</li> + <li>JSON은 JSON내부에 포함할 수 있는 모든 형태의 데이터 타입을 취할 수 있습니다. 즉, 배열이나 오브젝트 외에도 단일 문자열이나 숫자또한 유효한 JSON 오브젝트가 됩니다.</li> + <li>자바스크립트에서 오브젝트 프로퍼티가 따옴표로 묶이지 않을 수도 있는 것과는 달리, JSON에서는 따옴표로 묶인 문자열만이 프로퍼티로 사용될 수 있습니다.</li> +</ul> + +<h2 id="해보면서_배우기_JSON을_다뤄_보자">해보면서 배우기: JSON을 다뤄 보자</h2> + +<p>웹사이트에서 JSON 데이터를 어떻게 사용할 수 있는지 예제를 통해 살펴봅시다.</p> + +<h3 id="시작하기">시작하기</h3> + +<p>우선 로컬 저장소에 <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/json/heroes.html">heroes.html</a> 와 <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/json/style.css">style.css</a> 파일을 복사해주세요. style.css 파일은 페이지에 적용할 간단한 CSS를 담고 있으며, heros.html 파일은 간단한 body HTML을 담고 있습니다.</p> + +<pre class="brush: html notranslate"><header> +</header> + +<section> +</section></pre> + +<p>자바스크립트 코드를 담기 위한{{HTMLElement("script")}} 요소를 추가해 주세요. 현재는 두 줄의 코드만 작성되어 있습니다. {{HTMLElement("header")}} 와 {{HTMLElement("section")}} 요소를 참조하여 변수에 담는 코드입니다. :</p> + +<pre class="brush: js notranslate">var header = document.querySelector('header'); +var section = document.querySelector('section');</pre> + +<p>JSON 데이터를 다음 깃허브 링크에서 가져올수 있습니다. <a href="https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json">https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json</a>.</p> + +<p>페이지에 JSON 데이터를 로딩하고 DOM 조작을 통해 아래와 같이 만들어 봅시다. :</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13857/json-superheroes.png" style="display: block; margin: 0 auto;"></p> + +<h3 id="JSON_가져오기">JSON 가져오기</h3> + +<p>JSON을 가져오기 위해서는, {{domxref("XMLHttpRequest")}} (때론 <strong>XHR</strong>)로 불리는 API를 사용하면 된다. 이것은 매우 유용한 JavaScript 오브젝트로 JavaScript (e.g. images, text, JSON, even HTML snippets)를 통해 우리가 서버로 부터 다양한 리소스를 가져오는 요청을 만들어 준다. 즉, 전체 페이지를 불러오지 않고도 필요한 부분만을 업데이트 할 수 있다. 이 기능은 좀 더 효과적으로 반응형 웹페이지을 다루는데 흥미로울 수 있으나, 아쉽게도 이 내용에 대한 자세한 부분은 여기서 다루지 않는다.</p> + +<ol> + <li>일단, 변수로 둘 JSON의 URL을 가져와야 합니다. 아래의 코드를 당신의 JavaScript 코드 내에 추가해 주세요. + <pre class="brush: js notranslate">var requestURL = 'https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json';</pre> + </li> + <li>요청을 만들기 위해, 우리는 <code>new</code> 키워드를 이용하여 <code>XMLHttpRequest</code> 생성자로부터 새로운 request 인스턴스를 생성해야 합니다. 아래의 코드를 추가해 주세요. + <pre class="brush: js notranslate">var request = new XMLHttpRequest();</pre> + </li> + <li>이제 <code><a href="/en-US/docs/Web/API/XMLHttpRequest/open">open()</a></code> 메소드를 사용해 새로운 요청을 만듭니다. 아래의 코드를 추가해 주세요. + <pre class="brush: js notranslate">request.open('GET', requestURL);</pre> + + <p>이것은 최소 두 개의 매개변수를 가집니다. 다른 선택적 매개변수도 가능해요. 이건 단순 예제니깐 두 가지 필수 매개변수만 취할게요.</p> + + <ul> + <li>HTTP 메서드는 네트워크 요청을 만들 때 사용됩니다. 이 경우 <code><a href="/en-US/docs/Web/HTTP/Methods/GET">GET</a></code> 을 사용하는게 좋겠어요. 우린 그저 데이터를 가져오면 되니깐요.</li> + <li>URL은 요청을 보낼 곳을 지정합니다. 우리가 저장해 둔 JSON 파일의 URL로 지정할게요.</li> + </ul> + </li> + <li>다음으로, 아래의 두 줄을 추가해 주세요. <code><a href="/en-US/docs/Web/API/XMLHttpRequest/responseType">responseType</a></code> 을 JSON으로 설정했어요. XHR로 하여금 서버가 JSON 데이터를 반환할 것이며, 자바스크립트 객체로서 변환될 것이라는 걸 알게 하기 위해서죠. 이제 <code><a href="/en-US/docs/Web/API/XMLHttpRequest/send">send()</a></code> 메서드를 이용해 요청을 보냅시다. + <pre class="brush: js notranslate">request.responseType = 'json'; +request.send();</pre> + </li> + <li>마지막 부분은 서버의 응답을 기다리고, 그것의 처리까지와 관련된 섹션입니다. 코드 아래에 다음의 코드를 추가해 주세요. + <pre class="brush: js notranslate">request.onload = function() { + var superHeroes = request.response; + populateHeader(superHeroes); + showHeroes(superHeroes); +}</pre> + </li> +</ol> + +<p>우리는 요청에 대한 응답을 <code>superHeroes</code>라는 변수에 저장할 겁니다.(<code><a href="/en-US/docs/Web/API/XMLHttpRequest/response">response</a></code> 프로퍼티로 가능) 이 변수는 이제 JSON 데이터에 기반한 자바스크립트 객체를 포함하게 됩니다! 두 개의 함수를 호출해 이 객체를 전달합시다. 하나는 <<code>header></code> 를 적절한 데이터로 채울 것이고, 다른 하나는 팀의 각 히어로에 대한 정보 카드를 생성하여 <code><section></code>내에 집어넣을 겁니다.</p> + +<p>우리는 로드 이벤트가 request 객체에 발생할 때에 작동하는 이벤트 핸들러 내에 코드를 넣었습니다. (<code><a href="/en-US/docs/Web/API/XMLHttpRequestEventTarget/onload">onload</a></code> 참고) 왜냐하면 응답이 성공적으로 돌아왔을 때만 로드 이벤트가 작동하기 때문입니다. 이러한 방식은 우리가 무언가를 시도하려고 할 때 <code>request.response</code> 가 확실히 가능하다는 것을 보장해 줍니다.</p> + +<h3 id="헤더_조작하기">헤더 조작하기</h3> + +<p>우린 JSON 데이터를 가져왔고, 그것을 자바스크립트 객체로 변환했어요. 이제 우리가 위에서 언급한 두 개의 함수를 사용함으로써 이것을 활용해 봅시다. 우선, 이전 코드 아래에 다음 함수 정의를 추가해 주세요.</p> + +<pre class="brush: js notranslate">function populateHeader(jsonObj) { + var myH1 = document.createElement('h1'); + myH1.textContent = jsonObj['squadName']; + header.appendChild(myH1); + + var myPara = document.createElement('p'); + myPara.textContent = 'Hometown: ' + jsonObj['homeTown'] + ' // Formed: ' + jsonObj['formed']; + header.appendChild(myPara); +}</pre> + +<p>우리는 이 매개변수를 <code>jsonObj</code>라고 이름 붙였습니다. 여러분으로 하여금 이 자바스크립트 객체가 JSON으로 부터 생겨났다는 걸 상기시켜 주기 위해서죠. 첫번째로 <code><a href="/en-US/docs/Web/API/Document/createElement">createElement()</a></code>로 {HTMLElement("h1")}} 요소를 생성하고, 이것의 <code><a href="/en-US/docs/Web/API/Node/textContent">textContent</a></code>를 객체의 <code>squadName</code> 프로퍼티와 같도록 만들어 준 뒤, <code><a href="/en-US/docs/Web/API/Node/appendChild">appendChild()</a></code>를 사용해서 헤더에 붙이도록 했습니다. We then do a very similar 이와 비슷한 과정을 paragraph에도 적용했죠. 생성하고,그것의 text content를 설정하고 헤더에 붙이도록요. 차이점이라면 그것의 텍스트가 객체의 <code>homeTown</code> 과 <code>formed</code> 프로퍼티를 포함한 문자열로 설정된 거예요.</p> + +<h3 id="히어로_정보_카드_만들기">히어로 정보 카드 만들기</h3> + +<p>자, 다음으로 슈퍼히어로 카드를 생성하고 보여줄 함수를 코드의 마지막에 추가해 주세요.</p> + +<pre class="brush: js notranslate">function showHeroes(jsonObj) { + var heroes = jsonObj['members']; + + for (var i = 0; i < heroes.length; i++) { + var myArticle = document.createElement('article'); + var myH2 = document.createElement('h2'); + var myPara1 = document.createElement('p'); + var myPara2 = document.createElement('p'); + var myPara3 = document.createElement('p'); + var myList = document.createElement('ul'); + + myH2.textContent = heroes[i].name; + myPara1.textContent = 'Secret identity: ' + heroes[i].secretIdentity; + myPara2.textContent = 'Age: ' + heroes[i].age; + myPara3.textContent = 'Superpowers:'; + + var superPowers = heroes[i].powers; + for (var j = 0; j < superPowers.length; j++) { + var listItem = document.createElement('li'); + listItem.textContent = superPowers[j]; + myList.appendChild(listItem); + } + + myArticle.appendChild(myH2); + myArticle.appendChild(myPara1); + myArticle.appendChild(myPara2); + myArticle.appendChild(myPara3); + myArticle.appendChild(myList); + + section.appendChild(myArticle); + } +}</pre> + +<p>우선, 새로운 변수 내의 자바스크립트 객체에 <code>members</code> 프로퍼티를 저장해 주세요. 이 배열은 각 히어로에 대한 정보를 가진 여러 개의 객체를 포함합니다.</p> + +<p>다음으로, 우리는 <a href="/en-US/docs/Learn/JavaScript/Building_blocks/Looping_code#The_standard_for_loop">for loop</a>를 사용하여 배열 내의 각 객체에 반복 실행을 걸겁니다.</p> + +<ol> + <li>몇 개의 새로운 요소를 생성해 주세요: <code><article></code>, <code><h2></code>, 3개의 <code><p></code>, 그리고 <code><ul></code>.</li> + <li><h2>가 히어로의 <code>name</code>을 가지도록 설정해 주세요.</li> + <li>목록 내의 정보를 소개하기 위해 세 개의 paragraph 안에 그들의 <code>secretIdentity</code>, <code>age</code>, 그리고 "Superpowers:" 라는 문장을 넣어 주세요.</li> + <li><code>superPowers</code> 라는 새로운 변수 안에 <code>powers</code>프로퍼티를 저장해 주세요. 이것은 현재 히어로의 초능력(superpower)을 열거한 배열을 포함합니다.</li> + <li>현재 히어로의 초능력을 반복 실행할 또다른 <code>for</code> 반복문을 사용합니다. 하나의 객체씩 <code><li></code> 를 생성하고, 그 안에 초능력을 집어 넣고, <code>appendChild()</code>를 사용하여 '<code>myList'</code> 라는 <code><ul></code> 안에 <code>listItem</code> 을 집어 넣습니다.</li> + <li>마지막으로 <code><article></code> (<code>myArticle</code>) 안에 <code><h2></code>, <code><p></code>, 그리고 <code><ul></code> 넣은 뒤, <code><section></code> 안에 <code><article></code>을 넣어 줍니다. 요소가 추가되어 지는 순서가 중요해요.왜냐하면 HTML 내에 보여질 거거든요.</li> +</ol> + +<div class="note"> +<p><strong>Note</strong>: 만약 실습에 문제를 겪고 있다면, <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/json/heroes-finished.html">heroes-finished.html</a> 코드를 참조하세요. (<a href="http://mdn.github.io/learning-area/javascript/oojs/json/heroes-finished.html">running live</a> 또한 보세요.)</p> +</div> + +<div class="note"> +<p><strong>Note</strong>: 만약 우리가 주로 사용하는 JavaScript 객체에 접근하기 위한 점/괄호 표기법을 따르는데 문제를 겪고 있다면, 다른 탭이나 당신의 선호하는 텍스트 에디터에 <a href="http://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json">superheroes.json</a> 파일을 여는 것이 도움이 될 것이다. 또한 당신은 점/괄호 표기법에 대한 다른 정보를 위해 <a href="/en-US/docs/Learn/JavaScript/Objects/Basics">JavaScript object basics</a> 글을 다시 확인하는 것을 권합니다.</p> +</div> + +<h2 id="객체와_문자_사이의_변환">객체와 문자 사이의 변환</h2> + +<p>위의 예제는 자바스크립트 객체에 접근한다는 관점에서 단순한 편이었죠. 왜냐하면 자바스크립트 객체를 사용해 우리는 XHR 요청을 곧장 JSON 응답으로 변환했으니깐요.</p> + +<pre class="brush: js notranslate">request.responseType = 'json';</pre> + +<p>하지만 우리는 이따금 재수 없어요. 때때로 우리는 날것의 JSON 문자열을 받기도 하고, 그것을 우리 스스로가 객체로 변환시켜야 할 때도 생기거든요. 그리고 네트워크를 통해 자바스크립트 객체를 보내고 싶을 때도 우리는 전송 전에 그걸 JSON(문자열)로 변환시켜야 해요. 다행히도, 이 두가지 문제가 웹 개발에 있어서 매우 흔한 덕에 다음과 같은 두가지 방법을 포함한 JSON 내장 객체가 브라우저 내에서 이용 가능합니다. </p> + +<ul> + <li><code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse">parse()</a></code>: JSON 문자열을 매개변수로서 수용하고, 일치하는 자바스크립트 객체로서 변환합니다.</li> + <li><code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify">stringify()</a></code>: 객체를 매개변수로서 수용하고, JSON 문자열 형태로 변환합니다. </li> +</ul> + +<p> 당신은 예제인 <a href="http://mdn.github.io/learning-area/javascript/oojs/json/heroes-finished-json-parse.html">heroes-finished-json-parse.html</a>에서 첫번째 동작을 확인할 수 있습니다.(아래 코드 참고-<a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/json/heroes-finished-json-parse.html">source code</a>) — JSON 텍스트를 반환하기 위한 추가한 XHR와 JavaScript 객체로 전환하기 위해 사용된 <code>parse()</code>제외하면 이 코드는 이전에 우리가 빌드한 것과 완전히 같은 코드입니다. 다음은중요한 코드의 일부입니다.:</p> + +<pre class="brush: js notranslate">request.open('GET', requestURL); +request.responseType = 'text'; // now we're getting a string! +request.send(); + +request.onload = function() { + var superHeroesText = request.response; // get the string from the response + var superHeroes = JSON.parse(superHeroesText); // convert it to an object + populateHeader(superHeroes); + showHeroes(superHeroes); +}</pre> + +<p>예상했겠지만, <code>stringify()</code> 는 반대의 방식으로 작용됩니다. 다음 나오는 코드 라인들을 당신의 브라우저 JavaScript 콘솔에 동작을 확인하면서 한 줄씩 입력해봅시다.:</p> + +<pre class="brush: js notranslate">var myJSON = { "name": "Chris", "age": "38" }; +myJSON +var myString = JSON.stringify(myJSON); +myString</pre> + +<p>이 페이지에서는 우리는 JavaScript 객체를 생성하고 있으며 이 객체가 무엇을 포함하고 있는지 확인하고 <code>stringify()</code> —반환된 값을 새로운 변수에 저장합니다—를 사용해서 JSON 문자열로 변환시켰습니다. 다시 한 번 더 확인해 봅시다.</p> + +<h2 id="실력을_시험해보자!">실력을 시험해보자!</h2> + +<p> 당신은 이 글의 끝에 도달했지만 가장 중요한 정보들을 기억하고 있습니까? 다음 단계를 가기 전 당신이 얼마나 이 정보를 습득하고 있는지 확인할 수 있는 테스트를 할 수 있습니다. — <a href="https://wiki.developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Test_your_skills:_JSON">Test your skills: JSON</a></p> + +<h2 id="요약">요약</h2> + +<p> 이 글에서, 당신의 프로그램에서 JSON을 어떻게 생성하고 구성 요소를 파악할 수 있는지, 그리고 JSON 안에 묶여 있는 자료들에 어떻게 접근하는 방법을 포함한 JSON을 사용하기 위한 간단한 가이드를 제공했습니다. 다음 글에서는, 객체 지향적인 JavaScript에 대해 시작해 볼 것입니다.</p> + +<h2 id="참고">참고</h2> + +<ul> + <li><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON">JSON object reference page</a></li> + <li><a href="/en-US/docs/Web/API/XMLHttpRequest">XMLHttpRequest object reference page</a></li> + <li><a href="/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest">Using XMLHttpRequest</a></li> + <li><a href="/en-US/docs/Web/HTTP/Methods">HTTP request methods</a></li> + <li><a href="http://json.org">Official JSON web site with link to ECMA standard</a></li> +</ul> + +<p>{{PreviousMenuNext("Learn/JavaScript/Objects/Inheritance", "Learn/JavaScript/Objects/Object_building_practice", "Learn/JavaScript/Objects")}}</p> + +<h2 id="다음_단계">다음 단계</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Basics">Object basics</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object-oriented_JS">Object-oriented JavaScript for beginners</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object_prototypes">Object prototypes</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Inheritance">Inheritance in JavaScript</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/JSON">Working with JSON data</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object_building_practice">Object building practice</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Adding_bouncing_balls_features">Adding features to our bouncing balls demo</a></li> +</ul> diff --git a/files/ko/learn/javascript/objects/object-oriented_js/index.html b/files/ko/learn/javascript/objects/object-oriented_js/index.html new file mode 100644 index 0000000000..df1bf59c17 --- /dev/null +++ b/files/ko/learn/javascript/objects/object-oriented_js/index.html @@ -0,0 +1,287 @@ +--- +title: Object-oriented JavaScript for beginners +slug: Learn/JavaScript/Objects/Object-oriented_JS +tags: + - Article + - Beginner + - CodingScripting + - JavaScript + - Learn + - 'l10n:priority' +translation_of: Learn/JavaScript/Objects/Object-oriented_JS +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Objects/Basics", "Learn/JavaScript/Objects/Object_prototypes", "Learn/JavaScript/Objects")}}</div> + +<p class="summary">자, 이제 기초 단계를 벗어나서,객체지향 JavaScript (OOJS) 을 보도록 하죠 — 이 문서에서 객체지향 (OOP) 이론에 대한 기초를 훑어본 후, 자바스크립트가 생성자와 함수를 통해 객체 클래스 개념을 따라했는지, 그리고 어떻게 객체를 만드는지 알아볼겁니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">선수조건:</th> + <td>컴퓨터 기본지식, HTML과 CSS에 대한 기본적인 이해,자바스크립트에 어느 정도 익숙할 것 (see <a href="/ko/docs/Learn/JavaScript/First_steps">First steps</a> and <a href="/ko/docs/Learn/JavaScript/Building_blocks">Building blocks</a>). OOJS 기초 지식 (see <a href="/ko/docs/Learn/JavaScript/Object-oriented/Introduction">Introduction to objects</a>).</td> + </tr> + <tr> + <th scope="row">학습목표:</th> + <td>객체지향에 대한 기본 지식을 습득 하고, 객체 지향이 자바스크립트에 어떻게 적용되었는지 ( "모든 것은 객체다") 와 어떻게 생성자와 객체 인스턴스를 만드는지에 대해 이해한다.</td> + </tr> + </tbody> +</table> + +<h2 id="객체지향_프로그래밍_—_기초">객체지향 프로그래밍 — 기초</h2> + +<p>객체지향 프로그래밍(OOP)의 개요를 설명하는 것으로 시작하겠습니다. 지금 단계에서 OOP의 모든 것을 설명면 너무 복잡해서 혼란만을 가중시킬 것이기 때문에 최대한 간단히 설명하겠습니다. OOP의 기본 컨셉은 프로그램 내에서 표현하고자 하는 실 세계(real world)의 일들을 객체를 사용해서 모델링 하고, 객체를 사용하지 않으면 불가능 혹은 무지 어려웠을 일들을 쉽게 처리하는 방법을 제공한다는 것입니다.</p> + +<p>객체는 당신이 모델링하고자 하고자 하는 일이나 기능 혹은 필요한 행동들을 표현하는 프로그램 코드와 그와 연관된 데이터로 구성됩니다. 객체는 데이터(그리고, 함수 역시)를 감싸서 ,(공식적인 표현으로는 <strong>encapsulate</strong>) 객체 패키지(해당 객체를 참조하기 위한 이름. <strong>namespace </strong>라고도 불리죠)안에 보관합니다. 이는 계층 구조를 만드는데 용이하고 사용하기에도 쉽게 하기 위해서죠; 또한, 객체는 네트워크를 통해 쉽게 전송될 수 있도록 데이터를 저장하는 용도로도 많이 사용됩니다.</p> + +<h3 id="객체_템플릿_정의">객체 템플릿 정의</h3> + +<p>자, 학교의 선생님과 학생들의 정보를 보여주는 간단한 프로그램이 있다고 칩시다. 여기서는 OOP의 일반적인 개념만을 살펴볼 뿐이지, 특정 언어에 국한된 내용을 이야기하지는 않을겁니다.</p> + +<p>시작해보자면, <a href="/ko/docs/Learn/JavaScript/Objects/Basics">first objects article</a> 에서 배웠던 Person 객체로 돌아가봅시다. 거기서 "사람"에 대한 기초적인 데이터와 기능을 정의했었죠. "사람"을 구별할 수 있는 특징은 많습니다 (그들의 주소, 키,신발사이즈, DNA 프로필, 여권번호, 중요한 개인적 자실 등 ...) ,하지만 이 예제에서는 오직 이름, 나이, 성별 그리고 취미만을 다룰겁니다. 여기에 더불어 이 데이터를 기반으로 각 개인에 대한 간단한 소개말과 인사말을 표시할 수 있도록 할 겁니다 . 이런 과정을 <strong>추상화</strong> — 프로그래머의 의도에 맞추어 가장 중요한 것들만을 뽑아서 복잡한 것들을 보다 단순한 모델로 변환하는 작업 - 라고 합니다.<img alt="" src="https://mdn.mozillademos.org/files/13889/person-diagram.png" style="display: block; height: 219px; margin: 0px auto; width: 610px;"></p> + +<h3 id="실제_객체_생성">실제 객체 생성</h3> + +<p><strong>객체 인스턴스</strong>는 클래스를 통해서 만들 수 있습니다.— 객체는 클래스에 정의된 데이터와 함수를 갖습니다. Person클래스를 통해서, 실제 '사람' 객체를 생성할 수 있습니다.:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/15163/MDN-Graphics-instantiation-2-fixed.png" style="display: block; height: 702px; margin: 0px auto; width: 695px;"></p> + +<p>클래스로부터 객체의 인스턴스가 생성될 때는 클래스의 <strong>생성자 함수</strong> 가 호출됩니다.클래스에서 객체 인스턴스가 생성되는 일련의 과정을 인스턴스화(<strong>instantiation</strong>)라고 합니다 — 객체의 인스턴스는 클래스를 통해 만들어집니다.</p> + +<h3 id="특별한_클래스">특별한 클래스</h3> + +<p>자, 이번에는 일반적인 사람이 아니라 — 일반적인 사람보다 세분화된 선생님과 학생들이 필요합니다. OOP 에서는,특정 클래스를 기반으로 새로운 클래스를 만들 수 있습니다 — <strong>child 클래스</strong> 는 <strong>부모 클래스</strong>를<strong> </strong><strong>상속</strong> 받아서 만들어집니다. child 클래스는 상속을 통해 부모 클래스에 정의된 데이터와 함수를 고스란히 사용할 수 있습니다. 클래스마다 기능이 달라지는 부분이 있다면, 직접 해당 클래스에 원하는 기능을 정의할 수 있습니다.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13881/MDN-Graphics-inherited-3.png" style="display: block; height: 743px; margin: 0px auto; width: 700px;"></p> + +<p>이것은 매우 유용합니다. 이름,성별,나이 등과 같이 선생님과 학생이 공유하는 많은 공통적인 특징들을 한번만 정의해도 되기 때문이죠. 또한 서로 다른 클래스에 같은 기능을 따로 정의할 수도 있습니다. 정의된 각각의 기능은 서로 다른 namespace에 존재하기 때문입니다. 예를 들어, 학생의 인사는 "안녕, 난 [이름]이야." 와 같은 형식이 될 것입니다. (ex) 안녕, 난 샘이야.) 반면 선생님은 "안녕하세요, 제 이름은 [성] [이름]이고 [과목명]을 담당하고 있습니다." 와 같이 좀 더 격식있는 형식을 사용할 것입니다. (ex) 안녕하세요, 제 이름은 데이브 그리피스이고 화학을 담당하고 있습니다.)</p> + +<div class="note"> +<p><strong>노트</strong>: 혹시 궁금해 하실까봐 말씀드리면, 여러 객체 타입에 같은 기능을 정의할 수 있는 능력을 멋진 용어로 <strong>"다형성(polymorphism)"</strong> 이라고 합니다.</p> +</div> + +<p>이제 자식 클래스들로부터 객체 인스턴스를 만들 수 있습니다. 예를 들면 :</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13885/MDN-Graphics-instantiation-teacher-3.png" style="display: block; height: 743px; margin: 0px auto; width: 700px;"></p> + +<p>다음 부분에선, 어떻게 객체지향 프로그래밍 이론이 자바스크립트에 실제로 적용될 수 있는지 살펴보겠습니다.</p> + +<h2 id="생성자와_객체_인스턴스">생성자와 객체 인스턴스</h2> + +<p>자바스크립트는 객체와 그 기능을 정의하기 위해 <strong>생성자 함수</strong>라고 불리는 특별한 함수를 사용합니다. 이는 보통 우리가 얼마나 많은 객체들을 생성해야 할지 모르기 때문에 유용합니다. 생성자는 효율적으로 필요한 만큼 객체를 생성하고, 데이터와 함수들을 설정하는 방법을 제공합니다.</p> + +<p>생성자로부터 새로운 객체 인스턴스가 생성되면, 객체의 핵심 기능 (프로토타입에 의해 정의됩니다. <a href="/ko/docs/Learn/JavaScript/Objects/Object_prototypes">Object prototypes</a> 글에서 자세히 다룰 것입니다.)이 <strong>프로토타입 체인</strong>에 의해 연결됩니다.</p> + +<p>자바스크립트에서 생성자를 이용해 클래스를 만들고, 클래스에서 객체 인스턴스를 만드는 방법을 알아봅시다. 가장 먼저, 첫 객체 글에서 보았던 <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/introduction/oojs.html">oojs.html</a> 파일을 로컬에 새로 복사하십시오.</p> + +<h3 id="간단한_예제">간단한 예제</h3> + +<ol> + <li>어떻게 일반적인 함수를 이용해 한 사람을 정의할 수 있는지부터 보겠습니다. 이 함수를 <code>script</code> 태그 안에 추가하세요: + + <pre class="brush: js">function createNewPerson(name) { + var obj = {}; + obj.name = name; + obj.greeting = function() { + alert('Hi! I\'m ' + this.name + '.'); + }; + return obj; +}</pre> + </li> + <li>이제 이 함수를 호출하여 새로운 사람을 만들 수 있습니다. 브라우저의 자바스크립트 콘솔을 열어 다음 코드를 입력해보세요: + <pre class="brush: js">var salva = createNewPerson('Salva'); +salva.name; +salva.greeting();</pre> + 이것은 잘 작동하지만, 썩 깔끔하진 않습니다. 객체를 만들기를 원하는데, 왜 굳이 빈 객체를 만들고 내용을 채워 리턴해야 할까요? 다행스럽게도 자바스크립트는 생성자 함수의 형태로 간단한 단축 명령을 제공합니다. 하나 만들어 보도록 하죠!</li> + <li>이전의 createNewPerson 함수를 다음의 코드로 교체하세요: + <pre class="brush: js">function Person(name) { + this.name = name; + this.greeting = function() { + alert('Hi! I\'m ' + this.name + '.'); + }; +}</pre> + </li> +</ol> + +<p>생성자 함수는 클래스의 자바스크립트 버전입니다. 이 함수가 함수가 가질 것 같은 모든 특징을 가지고 있지만, 아무것도 리턴하지 않고 객체를 만들지도 않는다는 것을 깨달으셨나요? 생성자 함수는 단순히 프로퍼티와 메소드를 정의합니다. 또 이를 정의할 때 this 라는 키워드가 사용되고 있는 것을 보실 수 있습니다. 이것은 객체 인스턴스가 생성될 때마다, 객체의 <code>name</code> 프로퍼티가 생성자 함수 호출에서 전달된 name 값과 같아질 것이라고 말하고 있습니다. 그리고 <code>greeting()</code> 메소드 역시 생성자에서 전달된 name 값을 사용할 것입니다.</p> + +<div class="note"> +<p><strong>노트</strong>: 관습적으로, 생성자 함수명은 대문자로 시작하게 합니다. 이 규칙은 생성자 함수가 코드 안에서 잘 구별되도록 해줍니다.</p> +</div> + +<p>그래서 어떻게 생성자 함수를 호출하여 객체들을 만들까요?</p> + +<ol> + <li>이전 코드 아래에 다음 코드들을 추가하세요: + <pre class="brush: js">var person1 = new Person('Bob'); +var person2 = new Person('Sarah');</pre> + </li> + <li> + <p>코드를 저장하고 브라우저를 새로고침합니다. 자바스크립트 콘솔에 다음 코드를 입력해보세요:</p> + </li> + <li> + <pre class="brush: js">person1.name +person1.greeting() +person2.name +person2.greeting()</pre> + </li> +</ol> + +<p>멋지군요! 이제 두 객체가 페이지에 생성된 것이 보입니다. 각각은 서로 다른 namespace에 저장되어있습니다. 객체의 프로퍼티와 메소드들을 사용하려면, <code>person1</code> 또는 <code>person2</code>로부터 호출하여야 합니다. 두 객체의 기능은 따로 패키징되어 서로 충돌하지 않을 것입니다. 그리고 두 Person 객체는 각각 고유의 <code>name</code> 프로퍼티와 <code>greeting()</code> 메소드를 사용할 수 있습니다. 이 둘이 생성될 때 부여받은 자신의 <code>name</code> 값을 사용한다는 것에 주목하십시오. 이것이 <code>this</code>를 사용하는 매우 중요한 이유 중 하나입니다. 객체들은 다른 값이 아니라, 그들이 가진 고유의 값을 사용합니다.</p> + +<p>생성자 호출을 다시 봅시다:</p> + +<pre class="brush: js">var person1 = new Person('Bob'); +var person2 = new Person('Sarah');</pre> + +<p>각각의 경우, <code>new</code> 키워드가 브라우저에게 우리가 새로운 객체 인스턴스를 만들고 싶어한다는 것을 알려줍니다. 괄호로 감싸진 매개변수들과 함께 생성자 이름을 호출하고, 결과는 변수에 담겨집니다. 일반적인 함수가 호출되는 방식과 매우 유사하죠. 각각의 인스턴스는 다음 정의에 따라 생성됩니다.</p> + +<pre class="brush: js">function Person(name) { + this.name = name; + this.greeting = function() { + alert('Hi! I\'m ' + this.name + '.'); + }; +}</pre> + +<p>새 객체가 생성된 이후, <code>person1</code>과 <code>person2</code> 변수는 다음 객체들을 가지게 됩니다.</p> + +<pre class="brush: js">{ + name: 'Bob', + greeting: function() { + alert('Hi! I\'m ' + this.name + '.'); + } +} + +{ + name: 'Sarah', + greeting: function() { + alert('Hi! I\'m ' + this.name + '.'); + } +}</pre> + +<p>우리가 생성자 함수를 호출할 때마다 매번 <code>greeting()</code> 함수를 다시 정의하는 것이 보입니다. 최선의 방법은 아니죠. 이를 피하기 위해, 우리는 prototype에 함수를 정의합니다. 이를 차후에 다시 살펴보겠습니다.</p> + +<h3 id="생성자_완성시키기">생성자 완성시키기</h3> + +<p>위에서 살펴본 예제는 시작에 불과합니다. 최종적인 <code>Person()</code> 생성자를 만들어봅시다.</p> + +<ol> + <li>여태 작성한 코드를 지우고 아래의 생성자로 대체하세요. 원리는 이전의 예제와 똑같으며, 약간 더 복잡할 뿐입니다: + <pre class="brush: js">function Person(first, last, age, gender, interests) { + this.name = { + 'first': first, + 'last' : last + }; + this.age = age; + this.gender = gender; + this.interests = interests; + this.bio = function() { + alert(this.name.first + ' ' + this.name.last + ' is ' + this.age + ' years old. He likes ' + this.interests[0] + ' and ' + this.interests[1] + '.'); + }; + this.greeting = function() { + alert('Hi! I\'m ' + this.name.first + '.'); + }; +}</pre> + </li> + <li>이제 생성자로 객체 인스턴스를 만들기 위해, 아래에 이 코드를 추가하세요: + <pre class="brush: js">var person1 = new Person('Bob', 'Smith', 32, 'male', ['music', 'skiing']);</pre> + </li> +</ol> + +<p>이제 이전에 해보았듯이, 브라우저의 자바스크립트 콘솔에서 프로퍼티와 메소드를 사용할 수 있습니다:</p> + +<pre class="brush: js">person1['age'] +person1.interests[1] +person1.bio() +// etc.</pre> + +<div class="note"> +<p><strong>노트</strong>: 만약 실행에 문제가 생긴다면, 저희가 준비한 코드와 비교해보세요. <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/introduction/oojs-class-finished.html">oojs-class-finished.html</a> (<a href="http://mdn.github.io/learning-area/javascript/oojs/introduction/oojs-class-finished.html">또한 실제로 실행되는 모습을 보세요</a>).</p> +</div> + +<h3 id="추가_예제">추가 예제</h3> + +<p>이를 시작하기 위해서, 몇 개의 객체를 더 생성하는 코드를 추가해보세요. 그리고 생성된 객체 인스턴스의 멤버들을 사용하거나 바꿔보세요.</p> + +<p>더 나아가, 우리의 <code>bio()</code> 메소드엔 몇 가지 문제점이 있습니다. 먼저 결과가 항상 대명사 "He"를 포함한다는 점입니다. 생성된 사람이 여성이거나 다른 성별 분류를 가질지라도 말이죠. 그리고 <code>interests</code> 배열에 몇 개가 포함되어 있더라도 bio는 2개의 취미만을 출력합니다. 클래스 정의 (생성자)에서 이를 해결할 방법이 있을까요? 자유롭게 생성자를 수정해보세요. (약간의 조건문과 반복문이 필요할지도 모르겠습니다). 어떻게 성별에 따라, 혹은 취미의 개수에 따라 문장이 다르게 구성되어야할지 생각해보세요 .</p> + +<div class="note"> +<p><strong>노트</strong>: 하다가 막힌다면, 저희가 제공하는 <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/introduction/oojs-class-further-exercises.html">GitHub 저장소의 모법 답안</a> (<a href="http://mdn.github.io/learning-area/javascript/oojs/introduction/oojs-class-further-exercises.html">그리고 실행 버전</a>)을 참고하세요. 하지만 일단 직접 해보시죠!</p> +</div> + +<h2 id="객체_인스턴스를_생성하는_다른_방법들">객체 인스턴스를 생성하는 다른 방법들</h2> + +<p>여태까지 객체 인스턴스를 만드는 두 가지 방법을 살펴보았습니다. <a href="/ko/docs/Learn/JavaScript/Objects/Basics#Object_basics">객체 리터럴을 선언하는 방법</a>과, 생성자 함수를 사용하는 방법(위를 보세요)이죠.</p> + +<p>이것들은 잘 동작하지만, 다른 방법들도 있습니다. 웹에서 정보를 찾다가 마주칠 경우를 대비해 익숙해져보는 것도 좋을 것 같습니다.</p> + +<h3 id="Object()_생성자">Object() 생성자</h3> + +<p>첫번째로, 새 객체를 만들기 위해 <code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Object">Object()</a></code> 생성자를 사용할 수 있습니다. 네, 최초의 object 역시 생성자를 가지고 있습니다. 빈 객체를 생성하는 함수이죠.</p> + +<ol> + <li>브라우저의 자바스크립트 콘솔에 아래 코드를 입력해보세요: + <pre class="brush: js">var person1 = new Object();</pre> + </li> + <li>이는 빈 객체를 <code>person1</code> 변수에 담습니다. 이제 이 객체에 점 표기법이나 괄호 표기법을 이용해 프로퍼티와 메소드들을 추가할 수 있습니다. 이 예제 코드를 콘솔 창에 입력해보세요. + <pre class="brush: js">person1.name = 'Chris'; +person1['age'] = 38; +person1.greeting = function() { + alert('Hi! I\'m ' + this.name + '.'); +};</pre> + </li> + <li>사전에 프로퍼티와 메소드를 정의하기 위해, <code>Object()</code> 생성자의 파라미터로 객체 리터럴을 전달할 수도 있습니다. 이 예제 코드를 콘솔 창에 입력해보세요. + <pre class="brush: js">var person1 = new Object({ + name: 'Chris', + age: 38, + greeting: function() { + alert('Hi! I\'m ' + this.name + '.'); + } +});</pre> + </li> +</ol> + +<h3 id="create()_함수_사용">create() 함수 사용</h3> + +<p>생성자는 여러분의 코드에 규칙을 부여해줍니다. 일단 생성자를 만들어두면, 이를 이용해 원하는대로 인스턴스를 생성할 수 있고, 이 인스턴스가 어디서 유래했는지 명백합니다.</p> + +<p>하지만 몇몇 사람들은 객체 인스턴스들을 생성할 때 먼저 생성자를 만들기를 원하지 않습니다. 특히 그들이 적은 수의 객체만을 생성할 때 말이죠. 자바스크립트는 <code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/create">create()</a></code>라는 내장함수를 가지고 있어 이를 가능하게 해줍니다. 이를 이용하면, 이미 존재하는 객체를 이용해 새로운 객체를 만들 수 있습니다.</p> + +<ol> + <li>이전 섹션에서 완료한 예제를 브라우저에서 열어, 아래 코드를 콘솔창에 입력해보세요. + <pre class="brush: js">var person2 = Object.create(person1);</pre> + </li> + <li>이제 이 코드를 입력해보세요. + <pre class="brush: js">person2.name +person2.greeting()</pre> + </li> +</ol> + +<p><code>person2</code>가 <code>person1</code>을 기반으로 만들어졌습니다. 새 객체는 원 객체와 같은 프로퍼티와 메소드들을 가집니다. </p> + +<p><code>create()</code> 함수의 한 가지 단점은 익스플로러 8에서는 지원하지 않는다는 점입니다. 따라서 오래된 브라우저들까지 지원하고 싶다면 생성자를 사용하는 것이 효과적입니다.</p> + +<p>다음에 <code>create()</code> 함수의 효과에 대해 더 살펴보겠습니다.</p> + +<h2 id="요약">요약</h2> + +<p>이 글은 객체지향 이론을 요약하여 설명해줍니다. 모든 부분을 다루지는 않지만, 지금 어떤 것들을 다루고 있는지에 대한 아이디어 정도는 얻을 수 있습니다. 게다가 객체 인스턴스를 생성하는 여러가지 방법에 대해서도 알아보기 시작했습니다.</p> + +<p>다음 글에서는 자바스크립트 객체 프로토타입에 대해 탐험해보겠습니다.</p> + +<p>{{PreviousMenuNext("Learn/JavaScript/Objects/Basics", "Learn/JavaScript/Objects/Object_prototypes", "Learn/JavaScript/Objects")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Basics">Object basics</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object-oriented_JS">Object-oriented JavaScript for beginners</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object_prototypes">Object prototypes</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Inheritance">Inheritance in JavaScript</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/JSON">Working with JSON data</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object_building_practice">Object building practice</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Adding_bouncing_balls_features">Adding features to our bouncing balls demo</a></li> +</ul> + +<p> </p> diff --git a/files/ko/learn/javascript/objects/object_prototypes/index.html b/files/ko/learn/javascript/objects/object_prototypes/index.html new file mode 100644 index 0000000000..f2eaf03498 --- /dev/null +++ b/files/ko/learn/javascript/objects/object_prototypes/index.html @@ -0,0 +1,274 @@ +--- +title: Object prototypes +slug: Learn/JavaScript/Objects/Object_prototypes +tags: + - 객체 지향 + - 상속 + - 자바스크립트 + - 프로토타입 +translation_of: Learn/JavaScript/Objects/Object_prototypes +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Objects/Object-oriented_JS", "Learn/JavaScript/Objects/Inheritance", "Learn/JavaScript/Objects")}}</div> + +<p class="summary">Javascript에서는 객체를 상속하기 위하여 프로토타입이라는 방식을 사용합니다. 본 문서에서는 프로토타입 체인이 동작하는 방식을 설명하고 이미 존재하는 생성자에 메소드를 추가하기 위해 프로토타입 속성을 사용하는 법을 알아봅니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">선수조건:</th> + <td>컴퓨터 기본지식, HTML과 CSS에 대한 기본적인 이해,자바스크립트에 어느 정도 익숙할 것 (see <a href="/ko/docs/Learn/JavaScript/First_steps">First steps</a> and <a href="/ko/docs/Learn/JavaScript/Building_blocks">Building blocks</a>). OOJS 기초 지식 (see <a href="/ko/docs/Learn/JavaScript/Objects/Basics">Introduction to objects</a>).</td> + </tr> + <tr> + <th scope="row">학습목표:</th> + <td>Javascript 객체 프로토타입을 이해하고 프로토타입 체인이 어떻게 동작하는지, 또 프로토타입 속성에 새 메소드를 추가하는 방법을 배웁니다.</td> + </tr> + </tbody> +</table> + +<h2 id="프로토타입_기반_언어"> 프로토타입 기반 언어?</h2> + +<p>JavaScript는 흔히 <strong>프로토타입 기반 언어(prototype-based language)</strong>라 불립니다.— 모든 객체들이 메소드와 속성들을 상속 받기 위한 템플릿으로써 <strong>프로토타입 객체(prototype object)</strong>를 가진다는 의미입니다. 프로토타입 객체도 또 다시 상위 프로토타입 객체로부터 메소드와 속성을 상속 받을 수도 있고 그 상위 프로토타입 객체도 마찬가지입니다. 이를 <strong>프로토타입 체인(prototype chain)</strong>이라 부르며 다른 객체에 정의된 메소드와 속성을 한 객체에서 사용할 수 있도록 하는 근간입니다.</p> + +<p>정확히 말하자면 상속되는 속성과 메소드들은 각 객체가 아니라 객체의 생성자의 <code>prototype</code>이라는 속성에 정의되어 있습니다.</p> + +<p>JavaScript에서는 객체 인스턴스와 프로토타입 간에 연결(많은 브라우저들이 생성자의 <code>prototype</code> 속성에서 파생된 <code>__proto__</code> 속성으로 객체 인스턴스에 구현하고 있습니다.)이 구성되며 이 연결을 따라 프로토타입 체인을 타고 올라가며 속성과 메소드를 탐색합니다.</p> + +<div class="note"> +<p><strong>Note:</strong> 객체의 prototype(<code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/getPrototypeOf">Object.getPrototypeOf(obj)</a></code>함수 또는 deprecated 된 <code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/proto">__proto__</a></code>속성으로 접근 가능한)과 생성자의 <code>prototype</code> 속성의 차이를 인지하는 것이 중요합니다. 전자는 개별 객체의 속성이며 후자는 생성자의 속성입니다. 이 말은 <code>Object.getPrototypeOf(new Foobar())</code>의 반환값이 <code>Foobar.prototype</code>과 동일한 객체라는 의미입니다.</p> +</div> + +<p>자세히 알기 위해 예제를 하나 봅시다.</p> + +<h2 id="프로토타입_객체_이해하기">프로토타입 객체 이해하기</h2> + +<p><code>Person()</code> 생성자를 작성했던 예제 코드로 되돌아가 봅시다. — 브라우저로 예제 코드를 불러 오시구요. 이전 페이지에서 작업했던 예제 코드를 날려버렸다면 <a href="http://mdn.github.io/learning-area/javascript/oojs/introduction/oojs-class-further-exercises.html">oojs-class-further-exercises.html</a> 페이지를 방문해 주세요. (<a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/introduction/oojs-class-further-exercises.html">source code</a>도 보시구요).</p> + +<p>이 예제에서 생성자 함수를 정의했었습니다:</p> + +<pre class="brush: js">function Person(first, last, age, gender, interests) { + + // 속성과 메소드 정의 + this.first = first; + this.last = last; +//... +}</pre> + +<p>그리고 인스턴스도 하나 만들었구요:</p> + +<pre class="brush: js">var person1 = new Person('Bob', 'Smith', 32, 'male', ['music', 'skiing']);</pre> + +<p>Javascript 콘솔에서 "person1."을 치게 되면 브라우저는 아래처럼 해당 객체의 멤버 이름을 자동 완성 팝업으로 보여줄 것입니다:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13853/object-available-members.png" style="display: block; margin: 0 auto;"></p> + +<p>위에서 <code>person1</code>의 프로토타입 객체인 <code>Person()</code>에 정의된 멤버들 — <code>name</code>, <code>age</code>, <code>gender</code>, <code>interests</code>, <code>bio</code>, <code>greeting</code>을 볼 수 있습니다. 또한 — <code>watch</code>, <code>valueOf</code>처럼 <code>Person()</code>의 프로토타입 객체인 <code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Object">Object</a></code>에 정의된 다른 멤버들도 보실 수 있습니다. 이는 프로토타입 체인이 동작한다는 증거입니다.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13891/MDN-Graphics-person-person-object-2.png" style="display: block; height: 150px; margin: 0px auto; width: 700px;"></p> + +<p>그럼 실제로는 <code>Object</code>에 정의되어 있는 메소드를 <code>person1</code>에서 호출하면 어떻게 될까요?<br> + 아래 처럼 말이죠:</p> + +<pre class="brush: js">person1.valueOf()</pre> + +<p>이 메소드는 호출된 객체의 값을 단순 반환합니다. — 직접 실행해 보세요! 이때 일어나는 일은 아래와 같습니다:</p> + +<ul> + <li>브라우저는 우선 <code>person1</code> 객체가 <code>valueOf()</code> 메소드를 가지고 있는지 체크합니다.</li> + <li>없으므로 <code>person1</code>의 프로토타입 객체(<code>Person()</code> 생성자의 프로토타입)에 <code>valueOf()</code> 메소드가 있는지 체크합니다.</li> + <li>여전히 없으므로 <code>Person()</code> 생성자의 프로토타입 객체의 프로토타입 객체(<code>Object()</code> 생성자의 프로토타입)가 <code>valueOf()</code> 메소드를 가지고 있는지 체크합니다. 여기에 있으니 호출하며 끝납니다!</li> +</ul> + +<div class="note"> +<p><strong>Note</strong>: 프로토타입 체인에서 한 객체의 메소드와 속성들이 다른 객체로 <strong>복사되는 것이 아님</strong>을 재차 언급합니다. — 위에서 보시다 시피 체인을 타고 올라가며 접근할 뿐입니다.</p> +</div> + +<div class="note"> +<p><strong>Note</strong>: 특정 객체의 프로토타입 객체에 바로 접근하는 공식적인 방법은 없습니다. — Javascript 언어 표준 스펙에서<code>[[prototype]]</code>으로 표현되는 프로토타입 객체에 대한 "링크"는 내부 속성으로 정의되어 있습니다. ({{glossary("ECMAScript")}} 참조). 하지만 많은 수의 모던 브라우저들이 <code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/proto">__proto__</a></code> (앞뒤로 언더바 2개씩) 속성을 통해 특정 객체의 프로토타입 객체에 접근할 수 있도록 구현하였습니다. 예를 들자면 <code>person1.__proto__</code> 또는 <code>person1.__proto__.__proto__</code> 코드로 체인이 어떻게 구성되어 있는지 확인해 보세요!</p> + +<p>ECMAScript 2015부터는 <code>Object.getPrototypeOf(obj)</code> 함수를 통해 객체의 프로토타입 객체에 <strong>바로 접근할 수 있게</strong> 되었습니다..</p> +</div> + +<h2 id="프로토타입_속성_상속_받은_멤버들이_정의된_곳">프로토타입 속성: 상속 받은 멤버들이 정의된 곳</h2> + +<p>그럼 상속 받은 속성과 메소드들은 어디에 정의되어 있을까요? <code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Object">Object</a></code> 레퍼런스 페이지에 가시면 좌측에 수 많은 속성과 메소드들이 나열되어 있는 것을 볼 수 있습니다. — 위 스크린샷에서 person1가 상속받은 멤버들보다 훨씬 많죠. 일부는 상속 되었지만 나머지는 아닙니다. — 왜일까요?</p> + +<p>정답은 상속 받는 멤버들은 <code>prototype</code> 속성(sub-namespace라고도 하죠)에 정의되어 있기 때문입니다. — <code>Object.</code>로 시작하는게 아니라, <code>Object.prototype.</code>로 시작하는 것들이죠. <code>prototype</code> 속성도 하나의 객체이며 프로토타입 체인을 통해 상속하고자 하는 속성과 메소드를 담아두는 버킷으로 주로 사용되는 객체입니다.</p> + +<p>So <code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/watch">Object.prototype.watch()</a></code>, <code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/valueOf">Object.prototype.valueOf()</a></code>등등은, 생성자를 통해 새로 생성되는 인스턴스는 물론 <code>Object.prototype</code>을 상속 받는 객체라면 어떤 객체에서든지 접근할 수 있습니다.</p> + +<p><code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/is">Object.is()</a></code>, <code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/keys">Object.keys()</a></code>등 <code>prototype</code> 버킷에 정의되지 않은 멤버들은 상속되지 않습니다. 이 것들은 <code>Object()</code> 생성자에서만 사용할 수 있는 멤버들이죠.</p> + +<div class="note"> +<p><strong>Note</strong>: 척 보기엔 이상합니다. — 함수에 불과한 생성자에 멤버를 정의한다니요? 함수 역시 객체의 하나입니다 — 못 미더우시면 <code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Function">Function()</a></code> 생성자 레퍼런스 페이지를 확인해 보세요.</p> +</div> + +<ol> + <li>prototype 속성을 직접 확인해 볼 수 있습니다. — 예제로 돌아가서 Javascript console에 아래 코드를 타이핑 해 보세요: + <pre class="brush: js">Person.prototype</pre> + </li> + <li>출력되는 것이 별로 많지 않을 겁니다 — 아직 이 커스텀 생성자 프로토타입에 아무것도 정의하지 않았거든요! 기본적으로 생성자의 프로토타입은 비어있습니다. 이번에는 아래 코드를 실행해 봅시다: + <pre class="brush: js">Object.prototype</pre> + </li> +</ol> + +<p>위의 예제에서 확인했듯이 <code>Object</code>를 상속받은 객체에서 사용 가능한 수 많은 메소드들이 <code>Object</code>의 <code>prototype</code> 속성에 정의되어 있음을 알 수 있습니다.</p> + +<p>Javascript 전반에 걸쳐 프로토타입 체인 상속이 어떻게 구성되어 있는지 확인할 수 있습니다 — 전역 객체인 <code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/String">String</a></code>, <code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Date">Date</a></code>, <code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Number">Number</a></code>, <code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Array">Array</a></code>의 프로토타입에 정의된 메소드와 속성들을 체크해 보세요. 이 프로토타입 객체들에는 이미 많은 수의 메소드가 정의되어 있으며 이는 아래처럼 문자열 객체를 생성 했을 때:</p> + +<pre class="brush: js">var myString = 'This is my string.';</pre> + +<p><code>myString</code> 인스턴스가 생성되는 즉시 <code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/String/split">split()</a></code>, <code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/String/indexOf">indexOf()</a></code>, <code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/String/replace">replace()</a></code>등의 문자열을 위한 유용한 메소드들을 사용할 수 있는 이유입니다.</p> + +<div class="warning"> +<p><strong>Important</strong>: <code>prototype</code> 속성은 Javascript에서 가장 헷갈리는 명칭중 하나입니다. — 보통 <code>this</code>가 현재 객체의 프로토타입 객체를 가리킬 것이라 오해하지만 그렇지 않죠. (프로토타입 객체는 <code>__proto__</code> 속성으로 접근 가능한 내장 객체인 것 기억 하시나요?). 대신에 <code>prototyp</code>e 속성은 상속 시키려는 멤버들이 정의된 객체를 가리킵니다.</p> +</div> + +<h2 id="create()_다시보기">create() 다시보기</h2> + +<p>이전에 새 인스턴스를 생성하기 위해서 <code>Object.create()</code> 메소드를 사용하는 법을 알아 보았습니다.</p> + +<ol> + <li>예를 들어서 이전 예제에서 아래 코드를 Javascript console에서 실행했었다면: + <pre class="brush: js">var person2 = Object.create(person1);</pre> + </li> + <li><code>create()</code> 메소드가 실제로 하는 일은 주어진 객체를 프로토타입 객체로 삼아 새로운 객체를 생성합니다. 여기서 person2는 person1을 프로토타입 객체로 삼습니다. 아래 코드를 실행하여 이를 확인할 수 있습니다: + <pre class="brush: js">person2.__proto__</pre> + </li> +</ol> + +<p>콘솔 상에는 <font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">person1</span></font>이 출력됩니다.</p> + +<h2 id="생성자_속성">생성자 속성</h2> + +<p>모든 생성자 함수는 <code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor">constructor</a></code> 속성을 지닌 객체를 프로토타입 객체로 가지고 있습니다. 이 <code>constructor</code> 속성은 원본 생성자 함수 자신을 가리키고 있습니다. 다음 장에서 볼 수 있듯이 <code>Person.prototype</code> 속성(또는 위 절에서 언급된 아무 생성자 함수의 prototype 속성)에 정의된 속성들은 <code>Person()</code> 생성자로 생성된 모든 인스턴스에서 사용할 수 있습니다. 그러므로 person1과 person2에서도 constructor 속성에 접근할 수 있습니다.</p> + +<ol> + <li>예를 들어 아래 코드를 콘솔에서 실행해 보세요: + <pre class="brush: js">person1.constructor +person2.constructor</pre> + + <p>두 구문 모두 <code>Person()</code> 생성자 함수를 반환할 것입니다.</p> + + <p><code>constructor</code> 속성에 괄호를 붙이고 실행하여(인자가 필요하면 전달하구요) 새 인스턴스를 생성하는 트릭이 있습니다. 어쨌든 생성자도 함수의 일종이므로 괄호를 붙이면 실행할 수 있습니다; new 키워드를 통해 실행하면 함수를 인스턴스를 생성하기 위한 생성자로 사용할 수 있죠.</p> + </li> + <li>아래 코드를 실행해 보세요: + <pre class="brush: js">var person3 = new person1.constructor('Karen', 'Stephenson', 26, 'female', ['playing drums', 'mountain climbing']);</pre> + </li> + <li>새로 생성된 객체를 테스트 해보세요, 아래처럼요: + <pre class="brush: js">person3.name.first +person3.age +person3.bio()</pre> + </li> +</ol> + +<p>잘 동작함을 알 수 있습니다. 이런 방식을 자주 사용할 필요는 없지만 실행 도중 명시적인 생성자 함수를 예측할 수 없는 상황에서 인스턴스를 생성해야 하거나 하는 경우 유용하게 사용할 수 있는 방법입니다.</p> + +<p><code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor">constructor</a></code> 속성은 여러 사용법이 있습니다. 예를 들어 인스턴스의 생성자 이름이 필요한 경우 아래의 코드로 알아낼 수 있습니다:</p> + +<pre class="brush: js">instanceName.constructor.name</pre> + +<p>아래 코드도 시험해 보세요:</p> + +<pre class="brush: js">person1.constructor.name +</pre> + +<div class="note"> +<p><strong>Note</strong>: <code>constructor.name</code> 는 변경이 가능하므로(상속이나 바인딩, 전처리, 트랜스파일러 등에 의해) 복잡한 로직에 적용하기 위해서는 <code><a href="/ko/docs/Web/JavaScript/Reference/Operators/instanceof">instanceof</a></code> 연산자를 사용하세요.</p> +</div> + +<ol> +</ol> + +<h2 id="프로토타입_수정하기">프로토타입 수정하기</h2> + +<p><code><font face="Open Sans, arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;">생성자의 </span></font>prototype</code> 속성을 수정하는 법에 대해 알아봅시다(프로토타입에 메소드를 추가하면 해당 생성자로 생성된 모든 객체에서 사용 가능합니다).</p> + +<ol> + <li><a href="http://mdn.github.io/learning-area/javascript/oojs/introduction/oojs-class-further-exercises.html">oojs-class-further-exercises.html</a> 예제로 돌아가서 <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/introduction/oojs-class-further-exercises.html">source code</a>를 다운 받으세요. 기존 코드에 아래 샘플 코드를 추가하여 <code>prototype</code> 속성에 새 메소드를 추가하세요: + + <pre class="brush: js">Person.prototype.farewell = function() { + alert(this.name.first + ' has left the building. Bye for now!'); +};</pre> + </li> + <li>저장한 코드를 브라우저로 실행하고 콘솔에서 아래 코드를 실행해 보세요. + <pre class="brush: js">person1.farewell();</pre> + </li> +</ol> + +<p>생성자에서 지정했던 person의 name이 alert 창으로 출력되는 것을 확인할 수 있습니다. 매우 유용한 기능이지만 중요한 점은 prototype에 새 메소드를 추가하는 순간 동일한 생성자로 생성된 모든 객체에서 추가된 메소드를 바로 사용할 수 있다는 점입니다.</p> + +<p>잠시 정리해 봅시다. 예제에서는 생성자를 정의하고, 객체를 생성하였으며, 그 이후에 프로토타입에 새 메소드를 추가하였습니다:</p> + +<pre class="brush: js">function Person(first, last, age, gender, interests) { + + // 속성과 메소드 정의 + +} + +var person1 = new Person('Tammi', 'Smith', 32, 'neutral', ['music', 'skiing', 'kickboxing']); + +Person.prototype.farewell = function() { + alert(this.name.first + ' has left the building. Bye for now!'); +};</pre> + +<p>그런데도 person1에서 바로 farewell() 메소드를 사용할 수 있습니다 - 자동으로 업데이트 되기 때문이죠(역주:원문은 이런 뉘앙스입니다만 실제로는 프로토타입 객체는 모든 인스턴스에서 공유하기 때문에 정의하는 즉시 별도의 갱신 과정 없이 접근이 가능합니다).</p> + +<div class="note"> +<p><strong>Note</strong>: 코드가 잘 동작하지 않는다면 <a href="https://github.com/mdn/learning-area/blob/master/javascript/oojs/advanced/oojs-class-prototype.html">oojs-class-prototype.html</a> 코드를 참조하세요 (<a href="http://mdn.github.io/learning-area/javascript/oojs/advanced/oojs-class-prototype.html">running live</a> 페이지도 보시구요).</p> +</div> + +<p>prototype에 속성을 정의하는 경우는 별로 본 적이 없을겁니다. 왜냐면 별로 좋은 방법이 아니거든요. 속성을 추가할 때 아래와 같이 할 수 있습니다:</p> + +<pre class="brush: js">Person.prototype.fullName = 'Bob Smith';</pre> + +<p>사람들이 항상 밥 스미스로 부르지 않을 수 있으니 별로 좋은 방법 같지는 않아 보입니다. <code>fullname</code>을 <code>name.first</code>와 <code>name.last</code>로 나누어 보죠:</p> + +<pre class="brush: js">Person.prototype.fullName = this.name.first + ' ' + this.name.last;</pre> + +<p>이 경우 <code>this</code>는 함수 범위가 아닌 전역 범위를 가리키므로 코드가 의도대로 동작하지 않습니다. 이대로 실행해도 <code>undefined undefined</code>만 볼 수 있죠. 윗 절에서 프로토타입에 정의한 메소드 내에서는 정상적으로 동작하는데 이는 코드가 함수 범위 내에 있으며 객체의 멤버 함수로써 동작하기에 객체 범위로 전환되었기 때문입니다. 따라서 프로토타입에 상수(한 번 할당하면 변하지 않는 값)를 정의하는 것은 가능하지만 일반적으로 생성자에서 정의하는 것이 낫습니다.</p> + +<p>사실 일반적인 방식으로는 속성은 생성자에서, 메소드는 프로토타입에서 정의합니다. 생성자에는 속성에 대한 정의만 있으며 메소드는 별도의 블럭으로 구분할 수 있으니 코드를 읽기가 훨씬 쉬워집니다. 아래처럼요:</p> + +<pre class="brush: js">// 생성자에서 속성 정의 + +function Test(a, b, c, d) { + // 속성 정의 +} + +// 첫 메소드 정의 + +Test.prototype.x = function() { ... }; + +// 두번째 메소드 정의 + +Test.prototype.y = function() { ... }; + +// 그 외.</pre> + +<p>이런 패턴은 Piotr Zalewa의 <a href="https://github.com/zalun/school-plan-app/blob/master/stage9/js/index.js">school plan app</a> 예제 코드에서 볼 수 있습니다.</p> + +<h2 id="요약">요약</h2> + +<p>이 글에서는 객체 프로토타입에 대한 설명과 프로토타입 체인을 통해 다른 객체를 상속하는 방법, 프로토타입 속성과 생성자에 새 메소드를 추가하는 방법과 그와 관련된 지식을 다루고 있습니다.</p> + +<p>다음 글에서는 직접 만든 객체간의 상속을 구현하는 방법에 대해 알아봅시다.</p> + +<p>{{PreviousMenuNext("Learn/JavaScript/Objects/Object-oriented_JS", "Learn/JavaScript/Objects/Inheritance", "Learn/JavaScript/Objects")}}</p> + +<p> </p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Basics">Object basics</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object-oriented_JS">Object-oriented JavaScript for beginners</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object_prototypes">Object prototypes</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Inheritance">Inheritance in JavaScript</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/JSON">Working with JSON data</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Object_building_practice">Object building practice</a></li> + <li><a href="/en-US/docs/Learn/JavaScript/Objects/Adding_bouncing_balls_features">Adding features to our bouncing balls demo</a></li> +</ul> + +<p> </p> diff --git a/files/ko/learn/server-side/django/admin_site/index.html b/files/ko/learn/server-side/django/admin_site/index.html new file mode 100644 index 0000000000..086f4e99aa --- /dev/null +++ b/files/ko/learn/server-side/django/admin_site/index.html @@ -0,0 +1,357 @@ +--- +title: 'Django Tutorial Part 4: Django admin site' +slug: Learn/Server-side/Django/Admin_site +translation_of: Learn/Server-side/Django/Admin_site +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Django/Models", "Learn/Server-side/Django/Home_page", "Learn/Server-side/Django")}}</div> + +<p class="summary"><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a> website의 모델을 만들었으므로, 우리는 Django Admin 을 이용해서 "실제" book data를 추가할 것입니다. 첫째로 우리는 당신에게 관리자 사이트에 모델들을 등록는 방법과, 이후 어떻게 로그인해서 데이터를 만들지를 보여줄 것입니다. 끝으로는 Admin site를 더 개선할 수 있는 방법들에 대해서 알아볼 것입니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">사전 준비:</th> + <td>첫째로 완료하세요: <a href="/en-US/docs/Learn/Server-side/Django/Models">Django Tutorial Part 3: Using models</a>.</td> + </tr> + <tr> + <th scope="row">목적:</th> + <td>장고 관리자 사이트의 이득과 한계를 이해하고, 모델을 위한 여러 레코드들을 생성하기.</td> + </tr> + </tbody> +</table> + +<h2 id="개요">개요</h2> + +<p> 장고의 관리자 어플리케이션은 모델을 사용하여 당신이 만들고, 보고, 업데이트하고, 그리고 삭제하는 데에 사용할 수 있는 사이트 영역을 자동적으로 만드는 데에 사용할 수 있습니다. 이는 당신이 시간을 많이 절약할 수 있도록 돕고, 모델을 쉽게 테스트 할 수 있게 하며 당신이 정확한 데이터를 가지고 있다는 느낌을 가질수 있도록 돕습니다. 관리자 어플리케이션은 또한 웹 사이트의 유형에 따라 production의 데이터를 관리하는 데 유용합니다. 모델 중심 접근 방식은 모델에 관한 많은 불필요한 세부 사항을 사용자들에게 노출하는, 모든 사용자들에게 가장 좋은 방식이라고 말할 수 없기 때문에, 장고 프로젝트는 internal 데이터 관리만을(즉, 관리자, 또는 당신의 조직 안에 있는 사람들을 위한 사용만을) 위해서 사용하는 것을 추천합니다.</p> + +<p> 웹사이트 안에 관리자 어플리케이션을 포함시키기 위해 요구되는 모든 설정은 <a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">created the skeleton project</a>를 생성했을 때 자동적으로 완료됩니다(실제 종속성에 대한 정보는, 여기 <a href="https://docs.djangoproject.com/en/2.0/ref/contrib/admin/">Django docs here</a>를 확인하세요). 결과적으로, 모델을 관리자 어플리케이션에 추가하기 위해서 <strong>꼭 해야만</strong> 하는 것은 그것들을 등록하는(register) 것입니다. 이 글의 마지막에서 모델 데이터를 더 잘 나타내기 위한 관리자 영역의 추가적인 설정을 짧게 보여드리겠습니다.</p> + +<p>모델을 등록한 뒤로는 새로운 "superuser"를 만들어서 사이트에 로그인을 하며, 이후에는 books, 저자, book instances 그리고 장르를 만들 것입니다. 이것들은 다음 튜토리얼에서 만들기 시작할 뷰와 템플릿을 테스트할 때 유용할 것입니다.</p> + +<h2 id="Models_등록하기">Models 등록하기</h2> + +<p>첫째, catalog 어플리케이션 안의 <strong>admin.py</strong> 파일을 여세요 (<strong>/locallibrary/catalog/admin.py</strong>). 다음과 같을 겁니다 — <code>django.contrib.admin</code>을 이미 imoprt하고 있다는 것에 주의하세요:</p> + +<pre class="brush: python">from django.contrib import admin + +# Register your models here. +</pre> + +<p> 파일의 하단에 아래 텍스트를 복사 붙여넣기 해서 모델을 등록(register)하세요. 이 코드는 모델들을 import하고 그것들을 등록하기 위해 <code>admin.site.register</code> 를 호출합니다.</p> + +<pre class="brush: python">from catalog.models import Author, Genre, Book, BookInstance + +admin.site.register(Book) +admin.site.register(Author) +admin.site.register(Genre) +admin.site.register(BookInstance) +</pre> + +<div class="note"><strong> 주의</strong>: 책의 언어를 나타내기 위한 모델을 생성하는 도전과제를 수행했다면 (<a href="/en-US/docs/Learn/Server-side/Django/Models">see the models tutorial article</a>), 그 모델도 import 한 후 등록하세요!</div> + +<p> 이것은 모델이나 모델들을 사이트에 등록(register)하는 가장 간단한 방법입니다. 관리자 사이트는 커스터마이즈 범위가 넓고, 아래에서 모델을 등록하는 다른 방법들에 관해 다르겠습니다.</p> + +<h2 id="Superuser_만들기">Superuser 만들기</h2> + +<p> 관리자 사이트에 로그인하기 위해서는, 직원(<em>Staff)</em> 상태가 활성화 된 사용자 계정이 있어야 합니다. 레코드들을 보고 생성하기 위해서는 이 사용자가 모든 객체들을 관리하기 위한 허가가 있어야 합니다. 사이트에 대한 모든 접속 권한과 필요한 허가를 가진 "superuser" 계정을 manage.py를 사용해서만들 수 있습니다. </p> + +<p>superuser를 생성하기 위해<strong> manage.py</strong>와 같은 경로 안에서 아래 명령어를 호출하세요. username, 이메일 주소, 그리고 강력한 비밀번호를 입력해야 할 것입니다.</p> + +<pre class="brush: bash">python3 manage.py createsuperuser +</pre> + +<p> 이 명령어가 완료되면 새로운 superuser가 데이터베이스에 추가되었을 것입니다. 이제 로그인을 테스트할 수 있도록 개발 서버를 재시작 하세요:</p> + +<pre class="brush: bash">python3 manage.py runserver + +</pre> + +<h2 id="관리자_계정에_로그인하기">관리자 계정에 로그인하기</h2> + +<p> 사이트에 로그인하기 위해서는, /admin URL(예: <a href="http://127.0.0.1:8000/admin/">http://127.0.0.1:8000/admin</a>)을 열어서 새로운 superuser의 userid와 password를 입력하세요(세부 정보를 입력한 후에는 로그인 페이지로 리디렉션되고 /admin URL로 돌아갑니다).</p> + +<p> 이곳은 설치된 어플리케이션에 따라 그룹지어진 모든 모델들을 보여줍니다. 모델 이름을 클릭해서 모든 관련 레코드들의 목록을 볼 수 있고, 그 목록들을 클릭하여 수정할 수 있습니다. 또한 모델 오른쪽의 <strong>Add</strong> 링크를 클릭하여 그 타입의 레코드를 곧바로 생성할 수 있습니다.</p> + +<p><img alt="Admin Site - Home page" src="https://mdn.mozillademos.org/files/13975/admin_home.png" style="display: block; height: 634px; margin: 0px auto; width: 998px;"></p> + +<p><strong> </strong>Books 모델 오른쪽의<strong> Add</strong> 링크를 클릭해서 새로운 책을 만드세요(아래와 같은 화면이 보일 것입니다). 각 필드의 제목, 사용된 위젯의 타입 그리고 <code>help_text</code>(있는 경우)가 모델 안에서 지정한 값과 일치하는 방식에 유의하세요. </p> + +<p> 필드에 값들을 입력하세요. 해당 필드 옆에 있는 <strong>+</strong> 버튼을 눌러 새로운 저자나 장르를 생성할 수 있습니다 (이미 생성했다면 목록에서 값을 선택하세요). 모두 완료했다면 레코드를 저장하기 위해 <strong>SAVE</strong>, <strong>Save and add another</strong> 또는 <strong>Save and continue editing</strong>을 클릭할 수 있습니다.</p> + +<p><img alt="Admin Site - Book Add" src="https://mdn.mozillademos.org/files/13979/admin_book_add.png" style="border-style: solid; border-width: 1px; display: block; height: 780px; margin: 0px auto; width: 841px;"></p> + +<div class="note"> +<p><strong> 주의</strong>: 이 지점에서 어플리케이션에 몇 가지 책들, 저자 그리고 장르(예: 판타지)를 추가하면서 시간을 보내보세요. 각각 저자와 장르에 서로 다른 두 가지 책이 포함되어 있는지 확인하세요 (이렇게 하면 나중에 리스트(list)와 디테일 뷰(detail view)들을 구현할 때 그것들을 더욱 흥미롭게 만들어 줍니다).</p> +</div> + +<p> 책을 추가했다면, 상단 북마크 안의 <strong>Home</strong> 링크를 클릭해서 관리자 페이지로 되돌아가세요. 그리고 <strong>Books </strong>링크를 클릭해서 책들의 현재 목록을 나타내세요(아니면 다른 링크를 클릭해서 다른 모델의 목록을 보세요). 이제 몇 가지 책을 추가했으니, 목록은 아래 스크린샷과 비슷하게 보일 겁니다. 각 책의 제목이 보입니다; 이것은 지난 글에서 다뤘던 Book 모델의 <code>__str__()</code> 메소드가 반환한 값입니다.</p> + +<p><img alt="Admin Site - List of book objects" src="https://mdn.mozillademos.org/files/13935/admin_book_list.png" style="border-style: solid; border-width: 1px; display: block; height: 407px; margin: 0px auto; width: 1000px;"></p> + +<p> 이 리스트에서 원하지 않는 책의 왼쪽에 있는 체크박스를 선택하고, Action 드랍-다운 목록에서 delete... 동작을 선택한 후, <strong>Go</strong> 버튼을 클릭해 책을 삭제할 수 있습니다. 또한 <strong>ADD BOOK</strong> 버튼을 클릭해서 새로운 책들을 추가할 수 있습니다. </p> + +<p> 링크 안의 책 이름을 선택해서 책을 편집할 수 있습니다. 아래에 보여지는 책 모델의 편집 페이지는 "Add" 페이지와 거의 동일합니다. 페이지의 제목 (<em>Change book</em>)과 <strong>Delete</strong>, <strong>HISTORY</strong> 그리고 <strong>VIEW ON SITE</strong> 버튼들의 추가가 큰 차이점입니다(마지막 버튼은 모델에서 <code>get_absolute_url()</code> 메소드를 정의했기 때문에 나타납니다).</p> + +<p><img alt="Admin Site - Book Edit" src="https://mdn.mozillademos.org/files/13977/admin_book_modify.png" style="border-style: solid; border-width: 1px; display: block; height: 780px; margin: 0px auto; width: 841px;"></p> + +<p>이제 <strong>Home</strong> 페이지로 되돌아가서 (홈 링크를 사용해서) <strong>Author</strong> 와 <strong>Genre</strong> 목록들을 보세요 — 새로운 책들을 추가하면서 이미 몇 가지 목록들이 있겠지만, 조금 더 추가해도 됩니다.</p> + +<p> 아직 가지고 있지 않은 것은 Book Instance들입니다. 왜냐하면 Books에서 만들어지지 않았기 때문이죠( <code>BookInstance</code>에서 <code>Book</code>을 만들 수 있긴 하지만 — 이것은 <code>ForeignKey</code> 필드의 특성입니다). Home 페이지로 되돌아가서 연관된<strong> 추가(Add)</strong>버튼을 눌러 아래의 Add book Instance 화면을 나타내세요. 크고 전역적으로 고유한 id에 주의하세요. 이것은 도서관에서 한 권의 책을 개별적으로 식별하는 데 사용할 수 있습니다.</p> + +<p><img alt="Admin Site - BookInstance Add" src="https://mdn.mozillademos.org/files/13981/admin_bookinstance_add.png" style="border-style: solid; border-width: 1px; display: block; height: 514px; margin: 0px auto; width: 863px;"></p> + +<p> 각각의 책마다 여러 개의 레코드를 만드세요. 상태(Status)를 최소한 몇 개의 레코드는 대여 가능(Available)로 설정하고, 나머지는 대여 중(On loan)으로 설정하세요. 만약 상태가 대여 불가능(<strong>not</strong> Available)이면, 만기 날짜도 같이 설정하세요.</p> + +<p>이게 끝입니다! 관리자 사이트를 어떻게 설정하고 사용하는지 배웠습니다. 또한 <code>Book</code>, <code>BookInstance</code>, <code>Genre</code>, 그리고 <code>Author</code> 에 대한 레코드들을 생성했고, 뷰와 탬플릿을 생성할 때 이 레코드들을 사용할 수 있을 것입니다.</p> + +<h2 id="추가_설정(Advanced_configuration)">추가 설정(Advanced configuration)</h2> + +<p> 장고는 등록된(registered) 모델의 정보를 사용하여 기본적인 관리자 사이트를 만드는 일을 꽤 잘합니다:</p> + +<ul> + <li>각각의 모델은 모델의 <code>__str__()</code> 메소드로 생성된 문자열로 식별되는, 그리고 편집을 위한 세부 정보(detail views)/양식(forms)에 링크되어 있는 개별적인 레코드들의 목록을 가지고 있습니다. 기본적으로, 이 화면은 레코드에 대한 대량 삭제 작업을 수행할 수 있는 액션 메뉴를 상단에 가지고 있습니다.</li> + <li>레코드의 편집과 추가를 위한 모델 디테일 레코드 양식들은 모델 안의 모든 필드를 포함하고 있고, 그것들의 선언 순서에 따라 수직으로 배치되어 있습니다. </li> +</ul> + +<p> 사용하기 더욱 편하도록 인터페이스를 추가적으로 사용자화 할 수 있습니다. 당신이 할 수 있는 몇 가지 일은:</p> + +<ul> + <li>목록 뷰(List views): + <ul> + <li>각각의 레코드에 표시되는 추가적인 필드/정보를 추가하기. </li> + <li>날짜나 다른 선택 값(예: 책의 대여 상태)에 기초해서 어떤 레코드들이 목록지어질 지 선택하는 필터들 추가하기.</li> + <li>목록 뷰(list views) 안의 동작 메뉴(actions menu)에 추가적인 옵션을 추가하고 이 메뉴가 양식 위의 어디에 보여져야 할 지 선택하기.</li> + </ul> + </li> + <li>세부 뷰(Detail views): + <ul> + <li>표시할(혹은 제외할)필드, 따를 순서, 그루핑, 편집 가능할지 여부, 사용될 위젯, 방향(orientation) 등등을 선택하기.</li> + <li>인라인 편집(inline editing)기능을 넣기 위해 관련된 필드들을 레코드에 추가하기(예: 책 레코드의 저자 레코드를 생성하는 동안 책 레코드를 추가하고 편집할 수 있는 기능을 추가하기).</li> + </ul> + </li> +</ul> + +<p> 이 글에서는 LocalLibrary의 인터페이스를 향상시키기 위한 몇 가지 변경점을 알아볼 겁니다. 그것들은 <code>Book</code>과 <code>Author</code> 모델 목록에 더 많은 정보를 추가하고, 그리고 그것들의 편집 보기(edit views)의 레이아웃을 향상시키는 것을 포함합니다. <code>Language</code> 와 <code>Genre</code> 모델은 변경하지 않을 겁니다. 그들은 각각 하나의 필드만을 갖고 있기 때문에 변경하는 것에 대한 이득이 없습니다!</p> + +<p> 모든 관리자 사이트 사용자화(customisation) 선택들(choices)의 완벽한 레퍼런스(reference)를 <a href="https://docs.djangoproject.com/en/2.0/ref/contrib/admin/">The Django Admin site</a>(장고 문서)에서 찾을 수 있습니다.</p> + +<h3 id="ModelAdmin_클래스_등록하기">ModelAdmin 클래스 등록하기</h3> + +<p>관리자 인터페이스에서 모델이 보여지는 방식을 바꾸고 싶다면 <a href="https://docs.djangoproject.com/en/dev/ref/contrib/admin/#modeladmin-objects">ModelAdmin</a> 클래스(레이아웃을 나타내는)를 정의한 후 모델 안에 등록합니다.</p> + +<p> <code>Author</code> 모델부터 시작해 봅시다. catalog 어플리케이션의 <strong>admin.py</strong> 파일을 여세요 (<strong>/locallibrary/catalog/admin.py</strong>). 원래 있던 <code>Author</code> 모델에 대한 등록(registration)을 주석처리(#를 앞에 붙여서) 하세요:</p> + +<pre class="brush: js"># admin.site.register(Author)</pre> + +<p>이제 아래와 같이 새로운 <code>AuthorAdmin</code> 과 그것의 등록(registration)을 추가하세요.</p> + +<pre class="brush: python"># Define the admin class +class AuthorAdmin(admin.ModelAdmin): + pass + +# Register the admin class with the associated model +admin.site.register(Author, AuthorAdmin) +</pre> + +<p> 이제 우리는<code> Book</code> 그리고 <code>BookInstance</code>를 위한 <code>ModelAdmin</code> 클래스를 추가할 겁니다. 또다시 원본 등록(registrations)를 주석처리 해야 합니다:</p> + +<pre class="brush: js"># admin.site.register(Book) +# admin.site.register(BookInstance)</pre> + +<p>이제 새로운 모델들을 생성하고 등록하기 위해서; 이것의 설명을 위해, 우리는 모델들을 등록(register)하기 위해 <code>@register</code> 데코레이터(decorator)를 대신 사용합니다(이것은 <code>admin.site.register()</code> 구문과 정확히 똑같은 일을 합니다):</p> + +<pre class="brush: python"># Register the Admin classes for Book using the decorator +@admin.register(Book) +class BookAdmin(admin.ModelAdmin): + pass + +# Register the Admin classes for BookInstance using the decorator +@admin.register(BookInstance) +class BookInstanceAdmin(admin.ModelAdmin): + pass +</pre> + +<p> 현재 모든 관리자 클래스들은 비어있기 때문에("<code>pass"</code>를 보세요) 관리자 행동은 바뀌지 않았을 것입니다! 이제 우리는 모델 고유의 관리자 행동(behaviour)을 정의하기 위해 이것들을 확장할 수 있습니다.</p> + +<h3 id="목록_뷰(list_view)들을_설정하기">목록 뷰(list view)들을 설정하기</h3> + +<p>현재 Locallibrary는 모델의 <code>__str__()</code> 메소드에서 생성되는 객체 이름을 사용하여 모든 저자들을 목록짓습니다. 이것은 단지 몇 명의 저자만 있을 때는 괜찮지만, 수많은 저자가 있을 때는 겹치는 이름의 서로 다른 저자가 있을 겁니다. 그것들을 구분하거나, 아니면 그저 각각의 저자마다 흥미로운 정보를 보여주고 싶다면, <a href="https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_display">list_display</a> 를 사용해서 view에 추가적인 필드를 추가할 수 있습니다. </p> + +<p>아래 코드로 <code>AuthorAdmin</code> 클래스를 대체하십시오. 목록에 선언될 이름들은 필요한 순서대로 튜플(tuple)로 선언됩니다, 아래에 보시는 것 처럼요(이것들은 원래 모델에서 특정된 것과 같은 이름들입니다).</p> + +<pre class="brush: python">class AuthorAdmin(admin.ModelAdmin): + list_display = ('last_name', 'first_name', 'date_of_birth', 'date_of_death') +</pre> + +<p> 이제 웹사이트 안의 저자 목록으로 이동하세요. 위의 필드들이 아래와 같이 보여질 것입니다:</p> + +<p><img alt="Admin Site - Improved Author List" src="https://mdn.mozillademos.org/files/14023/admin_improved_author_list.png" style="border-style: solid; border-width: 1px; display: block; height: 302px; margin: 0px auto; width: 941px;"></p> + +<p>우리의 <code>Book</code> 모델을 위해서 추가적으로 <code>author</code> 그리고 <code>genre</code>를 표시해 봅시다. <code>author</code>는 <code>Foreignkey</code> 필드 관계(일-대-다)이기 때문에, 관련된 레코드의 <code>__str__()</code> 값에 의해 나타내어질 것입니다. 아래의 버전으로 <code>BookAdmin</code> 클래스를 대체하세요.</p> + +<pre class="brush: python">class BookAdmin(admin.ModelAdmin): + list_display = ('title', 'author', 'display_genre') +</pre> + +<p> 불행하게도 <code>genre</code> 필드는 <code>ManyToManyField</code>이기 때문에 <code>list_display</code>에 직접적으로 특정할 수 없습니다.(거대한 데이터베이스 접근 "비용"이 발생할 수 있기 때문에 장고는 이것을 방지합니다). 대신 정보를 문자열로 받기 위해서 <code>display_genre</code> 함수를 정의할 겁니다(이것이 위에서 호출한 함수입니다; 아래에서 함수를 정의하겠습니다).</p> + +<div class="note"> +<p><strong>주의</strong>: <code>genre</code> 를 가져오는 것은 좋은 생각이 아닙니다. 왜냐하면 데이터베이스 작동의 "비용"이 너무 높기 때문입니다. 모델 안의 호출 함수들이 다른 이유로도 굉장히 유용하기 때문에 — 예를 들자면 리스트 안의 모든 항목에 delete 링크를 추가하는 것 처럼요.</p> +</div> + +<p>아래 코드를 <code>Book</code> 모델(<strong>models.py</strong>) 안에 추가하세요. 이것은 <code>genre</code> 필드의 첫 세 가지 값들의 문자열을 생성합니다(만약 존재한다면요) 그리고 이 메소드를 위해 관리자 사이트에서 사용될 수 있는 <code>short_description</code> 을 만듭니다.</p> + +<pre class="brush: python"> def display_genre(self): + """Create a string for the Genre. This is required to display genre in Admin.""" + return ', '.join(genre.name for genre in self.genre.all()[:3]) + + display_genre.short_description = 'Genre' +</pre> + +<p> 모델을 저장하고 관리자를 업데이트 했다면, 웹사이트를 열어서 Books 목록 페이지로 이동하세요; 아래와 같은 책 리스트가 있을 것입니다:</p> + +<p><img alt="Admin Site - Improved Book List" src="https://mdn.mozillademos.org/files/14025/admin_improved_book_list.png" style="border-style: solid; border-width: 1px; display: block; height: 337px; margin: 0px auto; width: 947px;"></p> + +<p><code>Genre</code> 모델 (그리고 <code>Language</code> 모델도, 정의했다면) 은 단일 필드를 갖고 있기 때문에, 추가적인 필드를 보여주기 위해 추가적인 모델을 생성하는 것은 의미가 없습니다.</p> + +<div class="note"> +<p><strong>주의</strong>: 최소한 상태 그리고 예상되는 반납일을 보여주는 <code>BookInstance</code> 모델 목록을 업데이트 해봅시다 . 이것은 이 글의 마지막에 도전 과제로 추가되어 있습니다!</p> +</div> + +<h3 id="목록_필터_추가하기">목록 필터 추가하기</h3> + +<p> 목록 안에 있는 항목들이 아주 많다면, 그 중에 어떤 항목들만이 표시될 지 정할 수 있는 필터를 추가하는 것이 유용합니다. 이것은 <code>list_filter</code> 속성 안에서 필드들을 목록지어서 완료됩니다. 현재 <code style="font-style: normal; font-weight: normal;">BookInstanceAdmin</code> 클래스를 아래 코드 조각으로 대체하십시오.</p> + +<pre class="brush: python">class BookInstanceAdmin(admin.ModelAdmin): +<strong> list_filter = ('status', 'due_back')</strong> +</pre> + +<p> 목록 뷰(list view)는 이제 오른쪽에 필터 상자를 갖고 있을 겁니다. 값을 필터링하기 위해 날짜와 상태를 선택하는 방법에 주의하세요:</p> + +<p><img alt="Admin Site - BookInstance List Filters" src="https://mdn.mozillademos.org/files/14037/admin_improved_bookinstance_list_filters.png" style="height: 528px; width: 960px;"></p> + +<h3 id="세뷰_보기_레이아웃(detail_view_layout)_조직하기">세뷰 보기 레이아웃(detail view layout) 조직하기</h3> + +<p> 기본적으로, detail view들은 모든 필드들을 모델에 선언된 순서대로, 수직적으로 배치합니다. 당신은 선언 순서, 표시될(혹은 제외될) 필드들, 섹션들이 정보들을 조직하는 데 사용될 지 여부, 필드들이 수직적 또는 수평적으로 표시될 지 여부 그리고 심지어 관리자 양식에서 어떤 편집 위젯이 사용될 지 까지 변경할 수 있습니다.</p> + +<div class="note"> +<p><strong>주의</strong>: LocalLibrary 모델은 상대적으로 간단하기 때문에 레이아웃을 변경할 큰 필요성이 없습니다; 그러나 방법을 보여드리기 위해, 몇 가지 변경점을 만들 것입니다.</p> +</div> + +<h4 id="어떤_필드들이_보여지고_배치될_지_제어하기">어떤 필드들이 보여지고 배치될 지 제어하기</h4> + +<p>아래와 같이 <code>fields</code> 줄(굵은 글씨)을 추가하기 위해 <code>AuthorAdmin</code> 클래스를 업데이트 하세요:</p> + +<pre class="brush: python">class AuthorAdmin(admin.ModelAdmin): + list_display = ('last_name', 'first_name', 'date_of_birth', 'date_of_death') +<strong> fields = ['first_name', 'last_name', ('date_of_birth', 'date_of_death')]</strong> +</pre> + +<p><code>fields</code> 속성은 양식에 보여져야 할 필드들만을 순서대로 목록짓습니다. 필드들은 기본적으로 수직적으로 표시되지만, 추가적으로 그것들을 튜플 안에 그룹짓는다면 수평적으로 표시됩니다(위의 "date" 필드처럼요).</p> + +<p>웹사이트 안에서 저자 세부 사항 뷰로 이동하세요 — 이제 아래와 같이 보일겁니다:</p> + +<p><img alt="Admin Site - Improved Author Detail" src="https://mdn.mozillademos.org/files/14027/admin_improved_author_detail.png" style="border-style: solid; border-width: 1px; display: block; height: 282px; margin: 0px auto; width: 928px;"></p> + +<div class="note"> +<p><strong>주의</strong>: 당신은 또한 양식(form)에서 제외되어야 할 속성들의 목록을 선언하기 위해 <code>exclude</code> 속성을 사용할 수 있습니다 (모델 안의 다른 모든 속성들이 표시될 겁니다). </p> +</div> + +<h4 id="세부_뷰_구역_나누기(Sectioning_the_detail_view)">세부 뷰 구역 나누기(Sectioning the detail view)</h4> + +<p><a href="https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.fieldsets">fieldsets</a> 속성을 사용하여, 세부 양식 안의 연관된 모델 정보를 그룹화하기 위해 "sections"를 추가할 수 있습니다.</p> + +<p> <code>BookInstance</code> 안에서, 우리는 책이 무엇인지 (i.e. <code>name</code>, <code>imprint</code>, and <code>id</code>) 그리고 이것을 언제 빌릴 수 있는지 (<code>status</code>, <code>due_back</code>)에 대한 정보를 가지고 있습니다. 우리는 <code>BookInstanceAdmin</code> 클래스에 굵게 표시된 텍스트를 추가하여 이것들을 각각 다른 구역에 추가할 수 있습니다. </p> + +<pre class="brush: python">@admin.register(BookInstance) +class BookInstanceAdmin(admin.ModelAdmin): + list_filter = ('status', 'due_back') + +<strong> fieldsets = ( + (None, { + 'fields': ('book', 'imprint', 'id') + }), + ('Availability', { + 'fields': ('status', 'due_back') + }), + )</strong></pre> + +<p>각각의 섹션엔 고유한 제목(또는 제목을 원하지 않을 경우, <code>None</code>) 그리고 사전의 필드와 관련된 튜플이 있습니다 — 양식(format)은 묘사하기 복잡하지만, 바로 위의 코드 조각을 본다면 이해하기 상당히 쉽습니다.</p> + +<p>이제 웹사이트 안의 book instance view로 이동하세요; 이제 아래와 같은 양식이 보일겁니다:</p> + +<p><img alt="Admin Site - Improved BookInstance Detail with sections" src="https://mdn.mozillademos.org/files/14029/admin_improved_bookinstance_detail_sections.png" style="border-style: solid; border-width: 1px; display: block; height: 580px; margin: 0px auto; width: 947px;"></p> + +<h3 id="연관_레코드들의_인라인_편집(Inline_editing_of_associated_records)">연관 레코드들의 인라인 편집(Inline editing of associated records)</h3> + +<p>때때로 연관된 레코드들을 동시에 추가하는 것이 가능할 때도 있습니다. 예를 들어, 세부 사항 페이지에서 책 정보 그리고 특정한 복사본에 대한 정보 둘 다 가질 수도 있습니다.</p> + +<p>이것은 <a href="https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.inlines">inlines</a>를 선언해서 할 수 있고, <a href="https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.TabularInline">TabularInline</a> (수평적 레이아웃)타입 또는 <a href="https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.StackedInline">StackedInline</a> (기본 모델 레이아웃과 같은 수직적 레이아웃)을 선택할 수 있습니다. 아래 <code>BookAdmin</code> 근처의 굵게 표시된 줄을 추가하여 <code>BookInstance</code> 정보 인라인을 <code>Book</code> 세부 사항(detail)에 추가할 수 있습니다:</p> + +<pre class="brush: python"><strong>class BooksInstanceInline(admin.TabularInline): + model = BookInstance</strong> + +@admin.register(Book) +class BookAdmin(admin.ModelAdmin): + list_display = ('title', 'author', 'display_genre') +<strong> inlines = [BooksInstanceInline]</strong> +</pre> + +<p> 이제 웹사이트의 <code>Book</code> 을 위한 화면으로 이동하세요 — 화면의 하단에서 이제 이 책과 연관된 책 인스턴스(book instances)를 볼 수 있을 겁니다(책의 장르 필드 바로 아래에):</p> + +<p><img alt="Admin Site - Book with Inlines" src="https://mdn.mozillademos.org/files/14033/admin_improved_book_detail_inlines.png" style="border-style: solid; border-width: 1px; display: block; height: 889px; margin: 0px auto; width: 937px;"></p> + +<p> 이 경우 우리는 인라인된 모델의 모든 필드들을 추가하는, 테이블화된 인라인 클래스를 선언했습니다. 레이아웃을 위해 모든 종류의 추가적인 정보들을 지정할 수 있습니다. 표시할 필드, 그것들의 순서, 그것들이 읽기 전용인지 아닌지, 등등을 포함해서요. (더 많은 정보를 위해 <a href="https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.TabularInline">TabularInline</a> 를 보세요). </p> + +<div class="note"> +<p><strong>주의</strong>: 이 기능에는 몇 가지 고통스러운 한계가 있습니다! 위의 스크린샷에서 우리는 이미 존재하는 세 개의 책 인스턴스(book instance)와 그 아래에 새로운 책 인스턴스를 위한 세 개의 플레이스홀더(placeholder)를 가지고 있습니다(아주 비슷하게 보이지요!). 기본값으로 예비 책 인스턴스를 위한 플레이스를 홀더를 가지지 <strong>않고 </strong>새로운 북 인스턴스마다 <strong>새로운 북 인스턴스 링크 하나씩</strong> 추가하는 것이 좋습니다. 또는 <code>BookInstance</code>를 여기서는 읽기 불가(non-readable) 링크로 목록화하는 것도 좋구요. 전자는<code> BookInstanceInline</code> 모델 안의 <code>extra</code> 속성을 0으로 설정하여 완료할 수 있습니다. 직접 해보세요.</p> +</div> + +<h2 id="도전_과제">도전 과제</h2> + +<p>이 섹션에서 많은 것을 배웠기 때문에, 이젠 직접 몇 가지를 도전해 볼 차례입니다.</p> + +<ol> + <li><code>BookInstance</code> 목록 뷰에 책, 상태, 만기 날짜, 그리고 id(book, status, due back date, id)를 표시하기 위한 코드를 추가해 보세요(기본<code> __str__()</code> 텍스트 가 아닌).</li> + <li>Book/BookInstance에서 했던 것고 같은 접근법을 사용해서 Author 세부 사항 뷰에 Book 항목들의 인라인 목록(Inline listing)을 추가해 보세요.</li> +</ol> + +<ul> +</ul> + +<h2 id="요약">요약</h2> + +<p>이게 답니다! 이제 관리자 사이트를 어떻게 설정하는지에 대해 가장 간단한 방법으로 그리고 발전된 방법으로도 배웠습니다. superuser 만드는 방법, 관리자 사이트와 뷰들을 이동하는 방법, 레코드를 삭제 및 업데이트하는 방법 등등을 배웠습니다. 지금까지 여러 Books, BookInstances, Genres 그리고 Authors를 만들었고, 이것들은 우리가 우리만의 view와 탬플릿들을 만들었을 때 그곳에 목록화하여 나타낼 수 있을 것입니다.</p> + +<h2 id="추가_자료">추가 자료</h2> + +<ul> + <li><a href="https://docs.djangoproject.com/en/2.0/intro/tutorial02/#introducing-the-django-admin">Writing your first Django app, part 2: Introducing the Django Admin</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.0/ref/contrib/admin/">The Django Admin site</a> (Django Docs)</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Django/Models", "Learn/Server-side/Django/Home_page", "Learn/Server-side/Django")}}</p> + + + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Server-side/Django/Introduction">Django introduction</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/development_environment">Setting up a Django development environment</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Django Tutorial: The Local Library website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django Tutorial Part 2: Creating a skeleton website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Models">Django Tutorial Part 3: Using models</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Admin_site">Django Tutorial Part 4: Django admin site</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django Tutorial Part 5: Creating our home page</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Generic_views">Django Tutorial Part 6: Generic list and detail views</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Sessions">Django Tutorial Part 7: Sessions framework</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Authentication">Django Tutorial Part 8: User authentication and permissions</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Forms">Django Tutorial Part 9: Working with forms</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Testing">Django Tutorial Part 10: Testing a Django web application</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Django Tutorial Part 11: Deploying Django to production</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/web_application_security">Django web application security</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></li> +</ul> diff --git a/files/ko/learn/server-side/django/authentication/index.html b/files/ko/learn/server-side/django/authentication/index.html new file mode 100644 index 0000000000..44bb932043 --- /dev/null +++ b/files/ko/learn/server-side/django/authentication/index.html @@ -0,0 +1,707 @@ +--- +title: 'Django Tutorial Part 8: User authentication and permissions' +slug: Learn/Server-side/Django/Authentication +translation_of: Learn/Server-side/Django/Authentication +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Django/Sessions", "Learn/Server-side/Django/Forms", "Learn/Server-side/Django")}}</div> + +<p class="summary">이 튜토리얼에서는, 당신의 사이트에 그들의 계정으로 로그인을 어떻게 허락할 것인지, 그리고 그들의 로그인 여부와 그들에게 허가한 퍼미션에 따라서 사이트에서 무엇을 할 수 있게 하거나, 볼 수 있게 할 것인지에 대해서 알려줄 것입니다. 또한 예시의 일부분으로, 우리는 이 LocalLibrary website를 확장시켜서, 로그인, 로그아웃 페이지를 덧붙이고, 사용자와 staff들이 그들이 빌려간 책들을 볼 수 있는 특별한 페이지들도 추가할 것입니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">선행학습:</th> + <td>앞의 모든 튜토리얼을 모두 끝내세요. up to and including <a href="/en-US/docs/Learn/Server-side/Django/Sessions">Django Tutorial Part 7: Sessions framework</a>.</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>사용자 인증과 허가를 어떻게 셋업하고, 이용하는 지에 대해 이해하기</td> + </tr> + </tbody> +</table> + +<h2 id="개요">개요</h2> + +<p>Django는 인증과 권위 부여 ("허가") 시스템을 제공합니다. 이것은 <a href="/en-US/docs/Learn/Server-side/Django/Sessions">previous tutorial</a> 에서 논의된 session framework에서 찾아볼 수 있는데, 사용자의 credentials을 검증하고 사용자들이 행동들의 허가 여부를 정의합니다. 이 프레임워크는 <code>Users</code> 와 <code>Groups</code> (한 번에 한 명 이상의 유저에게 허가를 적용하는 일반적인 방법)을 위한 빌트인 모델을 포함하는데, permissions/flags는 that designate whether 사용자들이 일이나 , forms, 로그인 한 유저들의 뷰, 그리고 컨텐츠를 제한하는 뷰 툴을 조정합니다.</p> + +<div class="note"> +<p><strong>Note</strong>: Django의 인증시스템은 매우 일반적인 것을 목표로하기 때문에, 다른 웹사이트 인증시스템에서 제공하는 특정한 기능들을 제공하지 않습니다. 이런 문제에 대한 해결방법은 서드파티 솔루션을 이용하는 것입니다. 예를 들면, 로그인 시도 제한과 제3자에 대한 인증(e.g.OAuth)과 같은 기능들은 제공하지 않습니다.</p> +</div> + +<p>이 튜토리얼에서 우리는 <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a> website안에서의 유저 인증을 어떻게 활성화하는지 보여주고, 당신의 로그인, 로그아웃 페이지를 만들며 당신의 모델과 페이지에 대한 권한 및 그 조정에 대해서 살펴볼 것입니다. 우리는 인증과 허가(권한)을 사용해서 사용자나 사서가 빌린 책들을 표시할 것입니다.</p> + +<p>이 인증시스템은 매우 유연하므로 당신이 원한다면 단지 제공된 로그인 API를 호출하는 것만으로 scratch에서 온 당신의 URLs, forms, views와 templates를 작성할 수 있습니다. 그렇지만, 이 단계에서는 Django가 "보유한" 인증 views와 forms를 이용하여 우리의 로그인과 로그아웃페이지를 만들 것입니다. 우리는 여전히 어떤 템플릿들을 만들어야 합니다. 그러나, 이것들은 꽤 쉽습니다.</p> + +<p>우리는 어떻게 퍼미션을 만드는지, 그리고 로그인 상태와 퍼미션을 views와 templates에서 어떻게 체크하는지에 대해서도 보여줄 것입니다.</p> + +<h2 id="인증하도록_하기">인증하도록 하기</h2> + +<p>Authentication은 우리가 이미 <a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">skeleton website</a> 을 생성했을 때 (in tutorial 2) 자동적으로 생서되었으므로 이 점에서는 할 것이 없습니다..</p> + +<div class="note"> +<p><strong>Note</strong>: 설정을 위해 필요한 것들은 모두 django-admin startproject 명령을 이용하여 앱을 생성했을 때 끝났습니다. 사용자들과 모델 퍼미션을 위한 데이터베이스 테이블들은 우리가 처음으로 python manage.py migrate을 실행했을 때 만들어졌습니다.</p> +</div> + +<p>아래에서 보여주는 것과 같이, 설정은 settings.py파일에서 INSTALLED_APPS과 MIDDLEWARE 부분을 셋업하는 것입니다.</p> + +<pre class="brush: python notranslate">INSTALLED_APPS = [ + ... +<strong> 'django.contrib.auth', </strong>#Core authentication framework and its default models. +<strong> 'django.contrib.contenttypes', #</strong>Django content type system (allows permissions to be associated with models). + .... + +MIDDLEWARE = [ + ... +<strong> 'django.contrib.sessions.middleware.SessionMiddleware',</strong> #Manages sessions across requests + ... +<strong> 'django.contrib.auth.middleware.AuthenticationMiddleware',</strong> #Associates users with requests using sessions. + .... +</pre> + +<h2 id="users와_groups_만들기">users와 groups 만들기</h2> + +<p><a href="/en-US/docs/Learn/Server-side/Django/Admin_site">Django admin site</a>를 tutorial 4에서 봤을 때 이미 당신은 첫번째 유저를 만들었습니다. 이는 슈퍼유저로서 <code>python manage.py createsuperuser</code>라는 명령으로 만들었죠. 우리의 슈퍼 유저는 이미 인증이 되어있고 모든 허가 권한을 가지고 있으므로, 우리는 일반적인 사이트 유저를 대표하는 테스트 유저를 만들 것입니다. 우리의 <em>locallibrary</em> groups과 website logins을 위해서 우리는 admin 사이트를 이용할 것인데, 이것이 가장 빠른 방법 중에 하나입니다.</p> + +<div class="note"> +<p>Note: 당신은 아래에서 보여주는 것처럼 프로그램적으로 사용자를 추가할 수 있습니다. 만약에 사용자가 로그인하는 사이트를 개발한다면, 당신은 이것을 해야합니다. (사용자들이 admin site를 접근하게 해서는 안됩니다.)</p> + +<pre class="brush: python notranslate">from django.contrib.auth.models import User + +# Create user and save to the database +user = User.objects.create_user('myusername', 'myemail@crazymail.com', 'mypassword') + +# Update fields and then save again +user.first_name = 'John' +user.last_name = 'Citizen' +user.save() +</pre> +</div> + +<p>아래에서 우리는 첫번째 그룹과 그 그룹의 사용자를 만들 것입니다. 아직까지는 우리의 도서관 멤버로서 아무런 퍼미션도 부여하지는 않습니다. 그러나 나중에 필요하다면, 개인들에게 각각 하는 것보다는 그룹에 한번에 하는 것이 휠씬 쉬운 일입니다.</p> + +<p>개발서버를 시작하고, 웹브라우저를 통해 admin site(<a href="http://127.0.0.1:8000/admin/">http://127.0.0.1:8000/admin/</a>)에 접속하십시오. 그리고 당신의 superuser 계정으로 로그인하십시오. admin site의 최상위 단계에서는 "Django application"에 의해 소트된 당신의 모델들이 있습니다. Authentication and Authorisation 섹션에 있는 Users or Groups 링크를 클릭하여 현재의 등록된 기록들을 볼 수 있습니다.</p> + +<p><img alt="Admin site - add groups or users" src="https://mdn.mozillademos.org/files/14091/admin_authentication_add.png" style="border-style: solid; border-width: 1px; display: block; height: 364px; margin: 0px auto; width: 661px;"></p> + +<p>첫번째로 우리 도서관 멤버를 위한 새 그룹을 만듭시다.</p> + +<ol> + <li>Add버튼(Group 다음에 있는)을 클릭하여 새 그룹을 만듭니다; "Library Members"라는 이름을 넣으세요.</li> +</ol> + +<p><img alt="Admin site - add group" src="https://mdn.mozillademos.org/files/14093/admin_authentication_add_group.png" style="border-style: solid; border-width: 1px; display: block; height: 561px; margin: 0px auto; width: 800px;"></p> + + + +<ol> + <li>우리는 그룹을 위한 어떠한 권한도 필요하지 않습니다. 그러므로 <strong>SAVE </strong>를 누르세요. (you will be taken to a list of groups).</li> +</ol> + + + +<p>자 이제 사용자(user)를 만들어봅시다 :</p> + +<ol> + <li>admin 사이트의 홈페이지로 돌아가주세요.</li> + <li>Users 옆 <strong>Add</strong> 버튼을 클릭하여 user dialog를 열어줍니다.<img alt="Admin site - add user pt1" src="https://mdn.mozillademos.org/files/14095/admin_authentication_add_user_prt1.png" style="border-style: solid; border-width: 1px; display: block; height: 409px; margin: 0px auto; width: 800px;"></li> + <li>당신의 테스트 사용자(user)를 위해 적절한 사용자이름(<strong>Username)</strong> 과 비밀번호(<strong>Password</strong>/<strong>Password confirmation)</strong> 를 입력해주세요.</li> + <li>사용자(user)를 만들기 위해<strong> SAVE</strong> 를 눌러줍시다.<br> + <br> + 관리자 사이트는 새로운 유저를 만들고, <strong>username</strong>을 바꿀 수 있고 유저모델의 선택 필드에 정보를 추가할 수 있는 <em>Change user화면으로 즉각 당신에게 보여줄 것입니다. 이 필드들은 이름, 성, 이메일 주소, 유저 상태 및 권한 (오직 </em><strong>Active </strong>표시만 가능합니다)를 포함합니다. 더 밑으로 내려가면 당신의 그룹과 권한 유저와 관련된 중요한 날짜들(예를 들어 가입일과 마지막 로그인 날짜)을 기입할 수 있습니다. <img alt="Admin site - add user pt2" src="https://mdn.mozillademos.org/files/14097/admin_authentication_add_user_prt2.png" style="border-style: solid; border-width: 1px; display: block; height: 635px; margin: 0px auto; width: 800px;"></li> + <li>그룹 섹션에서, Available groups목록에서 <strong>Library Member</strong> 를 선택하고두 박스 사이에 있는<strong> 오른쪽 화살표</strong>를 누르면 Chosen groups box로 이동이 될 거에요<img alt="Admin site - add user to group" src="https://mdn.mozillademos.org/files/14099/admin_authentication_user_add_group.png" style="border-style: solid; border-width: 1px; display: block; height: 414px; margin: 0px auto; width: 933px;"></li> + <li>여기서는 아무것도 필요치 않습니다, 그저 <strong>SAVE</strong> 를 선택하고, 유저 목록으로 가십시오.</li> +</ol> + +<p>다됬습니다! 이제 당신은 테스트를 위해 사용할 수 있는 "normal library member" 계정을 갖게 되었습니다(이들이 로그인할 수 있도록 페이지를 만들 때 말이죠).</p> + +<div class="note"> +<p><strong>Note</strong>: 다른 도서관 유저 만들기를 시도해보아야 합니다. 또한 사서들을 위한 그룹을 만들고 유저를 추가해보세요!</p> +</div> + +<h2 id="authentication_views_세팅하기">authentication views 세팅하기</h2> + +<p>Django는 authentication pages에서 login, log out, and password 조정을 위한 거의 모든 것을 제공해 줍니다. "out of the box". 이것은 URL mapper, views와 forms들을 포함하지만 templates은 포함하지 않습니다 — 우리가 만들어야 하죠!</p> + +<p>여기서, 우리는 기본 시스템들에 LocalLibrary를 통합하고, template들을 만들 수 있는 지를 볼 거에요.그리고 이것들을 프로젝트 메인 URL들에 넣을 것입니다.</p> + +<div class="note"> +<p><strong>Note</strong>: 어떤 코드도 사용하지 않으셔도 되지만, 아마 스스로 원할 가능성이 높아요. 더 쉽게 해주거든요. 만약 user model을 바꾸고자 한다면, form을 다루는 코드를 바꾸게 될 가능성이 아주 높아요. (앞으로 나올 주제에요!) 그렇다고 하더라도, stock view 함수들은 사용할 수 있어야 합니다.</p> +</div> + +<div class="note"> +<p><strong>Note: </strong>이 경우에, catalog application에 URL과 템플릿을 포함해서 인authentication page들을 넣는게 합리적입니다. 그러나 많은 application들을 가지고 있다면, 공통적으로 로그인 해야하는 것을 분리하고 사이트 전체에서 로그인하는 것을 가능하게끔하는 게 좋을겁니다. 이게 우리가 여기서 볼려고하는 것이죠!</p> +</div> + +<h3 id="Project_URLs">Project URLs</h3> + +<p> (<strong>locallibrary/locallibrary/urls.py</strong>) 파일에 다음 코드를 추가해주세요:</p> + +<pre class="brush: python notranslate">#Add Django site authentication urls (for login, logout, password management) +urlpatterns += [ + path('accounts/', include('django.contrib.auth.urls')), +] +</pre> + +<p>이 URL( <a href="http://127.0.0.1:8000/accounts/">http://127.0.0.1:8000/accounts/</a>)로 접속하세요. URL ('/'의 연결에 주의하세요!) 그러면 장고는 이 URL을 찾을 수 없기 때문에 에러메세지를 보여줄겁니다. 그리고 그 URL들을 어디에서 찾았는지 시도했던 모든 리스트들도 보여줍니다. 이것으로부터 당신은 예를들면, 어떤 URL들이 작동되는지 볼 수 있습니다.</p> + +<div class="note"> +<p><strong>Note: </strong>Using the above method adds the following URLs with names in square brackets, which can be used to reverse the URL mappings. You don't have to implement anything else — the above URL mapping automatically maps the below mentioned URLs.</p> +</div> + +<div class="note"> +<pre class="brush: python notranslate">accounts/ login/ [name='login'] +accounts/ logout/ [name='logout'] +accounts/ password_change/ [name='password_change'] +accounts/ password_change/done/ [name='password_change_done'] +accounts/ password_reset/ [name='password_reset'] +accounts/ password_reset/done/ [name='password_reset_done'] +accounts/ reset/<uidb64>/<token>/ [name='password_reset_confirm'] +accounts/ reset/done/ [name='password_reset_complete']</pre> +</div> + +<p>Now try to navigate to the login URL (<a href="http://127.0.0.1:8000/accounts/login/">http://127.0.0.1:8000/accounts/login/</a>). This will fail again, but with an error that tells you that we're missing the required template (<strong>registration/login.html</strong>) on the template search path. You'll see the following lines listed in the yellow section up the top:</p> + +<pre class="brush: python notranslate">Exception Type: TemplateDoesNotExist +Exception Value: <strong>registration/login.html</strong></pre> + +<p>The next step is to create a registration directory on the search path and then add the <strong>login.html</strong> file.</p> + +<h3 id="Template_directory">Template directory</h3> + +<p>The URLs (and implicitly views) that we just added expect to find their associated templates in a directory <strong>/registration/</strong> somewhere in the templates search path.</p> + +<p>For this site, we'll put our HTML pages in the <strong>templates/registration/</strong> directory. This directory should be in your project root directory, i.e the same directory as the <strong>catalog</strong> and <strong>locallibrary</strong> folders). Please create these folders now.</p> + +<div class="note"> +<p><strong>Note:</strong> Your folder structure should now look like the below:<br> + locallibrary (Django project folder)<br> + |_catalog<br> + |_locallibrary<br> + |_templates <strong>(new)</strong><br> + |_registration</p> +</div> + +<p>To make these directories visible to the template loader (i.e. to put this directory in the template search path) open the project settings (<strong>/locallibrary/locallibrary/settings.py</strong>), and update the <code>TEMPLATES</code> section's <code>'DIRS'</code> line as shown.</p> + +<pre class="brush: python notranslate">TEMPLATES = [ + { + ... +<strong> 'DIRS': ['./templates',],</strong> + 'APP_DIRS': True, + ... +</pre> + +<h3 id="Login_template">Login template</h3> + +<div class="warning"> +<p><strong>Important</strong>: The authentication templates provided in this article are a very basic/slightly modified version of the Django demonstration login templates. You may need to customise them for your own use!</p> +</div> + +<p>Create a new HTML file called /<strong>locallibrary/templates/registration/login.html</strong>. give it the following contents:</p> + +<pre class="brush: html notranslate">{% extends "base_generic.html" %} + +{% block content %} + +{% if form.errors %} + <p>Your username and password didn't match. Please try again.</p> +{% endif %} + +{% if next %} + {% if user.is_authenticated %} + <p>Your account doesn't have access to this page. To proceed, + please login with an account that has access.</p> + {% else %} + <p>Please login to see this page.</p> + {% endif %} +{% endif %} + +<form method="post" action="{% url 'login' %}"> +{% csrf_token %} + +<div> + <td>\{{ form.username.label_tag }}</td> + <td>\{{ form.username }}</td> +</div> +<div> + <td>\{{ form.password.label_tag }}</td> + <td>\{{ form.password }}</td> +</div> + +<div> + <input type="submit" value="login" /> + <input type="hidden" name="next" value="\{{ next }}" /> +</div> +</form> + +{# Assumes you setup the password_reset view in your URLconf #} +<p><a href="{% url 'password_reset' %}">Lost password?</a></p> + +{% endblock %}</pre> + +<p id="sect1">This template shares some similarities with the ones we've seen before — it extends our base template and overrides the <code>content</code> block. The rest of the code is fairly standard form handling code, which we will discuss in a later tutorial. All you need to know for now is that this will display a form in which you can enter your username and password and that if you enter invalid values you will be prompted to enter correct values when the page refreshes.</p> + +<p>Navigate back to the login page (<a href="http://127.0.0.1:8000/accounts/login/">http://127.0.0.1:8000/accounts/login/</a>) once you've saved your template, and you should see something like this:</p> + +<p><img alt="Library login page v1" src="https://mdn.mozillademos.org/files/14101/library_login.png" style="border-style: solid; border-width: 1px; display: block; height: 173px; margin: 0px auto; width: 441px;"></p> + +<p>If you try to log in that will succeed and you'll be redirected to another page (by default this will be <a href="http://127.0.0.1:8000/accounts/profile/">http://127.0.0.1:8000/accounts/profile/</a>). The problem here is that by default Django expects that after login you will want to be taken to a profile page, which may or may not be the case. As you haven't defined this page yet, you'll get another error!</p> + +<p>Open the project settings (<strong>/locallibrary/locallibrary/settings.py</strong>) and add the text below to the bottom. Now when you log in you should be redirected to the site homepage by default.</p> + +<pre class="brush: python notranslate"># Redirect to home URL after login (Default redirects to /accounts/profile/) +LOGIN_REDIRECT_URL = '/' +</pre> + +<h3 id="Logout_template">Logout template</h3> + +<p>If you navigate to the logout URL (<a href="http://127.0.0.1:8000/accounts/logout/">http://127.0.0.1:8000/accounts/logout/</a>) then you'll see some odd behaviour — your user will be logged out sure enough, but you'll be taken to the <strong>Admin</strong> logout page. That's not what you want, if only because the login link on that page takes you to the Admin login screen (and that is only available to users who have the <code>is_staff</code> permission).</p> + +<p>Create and open /<strong>locallibrary/templates/registration/logged_out.html</strong>. Copy in the text below:</p> + +<pre class="brush: html notranslate">{% extends "base_generic.html" %} + +{% block content %} + <p>Logged out!</p> + <a href="{% url 'login'%}">Click here to login again.</a> +{% endblock %}</pre> + +<p>This template is very simple. It just displays a message informing you that you have been logged out, and provides a link that you can press to go back to the login screen. If you go to the logout URL again you should see this page:</p> + +<p><img alt="Library logout page v1" src="https://mdn.mozillademos.org/files/14103/library_logout.png" style="border-style: solid; border-width: 1px; display: block; height: 169px; margin: 0px auto; width: 385px;"></p> + +<h3 id="Password_reset_templates">Password reset templates</h3> + +<p>The default password reset system uses email to send the user a reset link. You need to create forms to get the user's email address, send the email, allow them to enter a new password, and to note when the whole process is complete.</p> + +<p>The following templates can be used as a starting point.</p> + +<h4 id="Password_reset_form">Password reset form</h4> + +<p>This is the form used to get the user's email address (for sending the password reset email). Create <strong>/locallibrary/templates/registration/password_reset_form.html</strong>, and give it the following contents:</p> + +<pre class="brush: html notranslate">{% extends "base_generic.html" %} + +{% block content %} + <form action="" method="post"> + {% csrf_token %} + {% if form.email.errors %} + \{{ form.email.errors }} + {% endif %} + <p>\{{ form.email }}</p> + <input type="submit" class="btn btn-default btn-lg" value="Reset password"> + </form> +{% endblock %} +</pre> + +<h4 id="Password_reset_done">Password reset done</h4> + +<p>This form is displayed after your email address has been collected. Create <strong>/locallibrary/templates/registration/password_reset_done.html</strong>, and give it the following contents:</p> + +<pre class="brush: html notranslate">{% extends "base_generic.html" %} + +{% block content %} + <p>We've emailed you instructions for setting your password. If they haven't arrived in a few minutes, check your spam folder.</p> +{% endblock %} +</pre> + +<h4 id="Password_reset_email">Password reset email</h4> + +<p>This template provides the text of the HTML email containing the reset link that we will send to users. Create <strong>/locallibrary/templates/registration/password_reset_email.html</strong>, and give it the following contents:</p> + +<pre class="brush: html notranslate">Someone asked for password reset for email \{{ email }}. Follow the link below: +\{{ protocol}}://\{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %} +</pre> + +<h4 id="Password_reset_confirm">Password reset confirm</h4> + +<p>This page is where you enter your new password after clicking the link in the password reset email. Create <strong>/locallibrary/templates/registration/password_reset_confirm.html</strong>, and give it the following contents:</p> + +<pre class="brush: html notranslate">{% extends "base_generic.html" %} + +{% block content %} + {% if validlink %} + <p>Please enter (and confirm) your new password.</p> + <form action="" method="post"> + {% csrf_token %} + <table> + <tr> + <td>\{{ form.new_password1.errors }} + <label for="id_new_password1">New password:</label></td> + <td>\{{ form.new_password1 }}</td> + </tr> + <tr> + <td>\{{ form.new_password2.errors }} + <label for="id_new_password2">Confirm password:</label></td> + <td>\{{ form.new_password2 }}</td> + </tr> + <tr> + <td></td> + <td><input type="submit" value="Change my password" /></td> + </tr> + </table> + </form> + {% else %} + <h1>Password reset failed</h1> + <p>The password reset link was invalid, possibly because it has already been used. Please request a new password reset.</p> + {% endif %} +{% endblock %} +</pre> + +<h4 id="Password_reset_complete">Password reset complete</h4> + +<p>This is the last password-reset template, which is displayed to notify you when the password reset has succeeded. Create <strong>/locallibrary/templates/registration/password_reset_complete.html</strong>, and give it the following contents:</p> + +<pre class="brush: html notranslate">{% extends "base_generic.html" %} + +{% block content %} + <h1>The password has been changed!</h1> + <p><a href="{% url 'login' %}">log in again?</a></p> +{% endblock %}</pre> + +<h3 id="Testing_the_new_authentication_pages">Testing the new authentication pages</h3> + +<p>Now that you've added the URL configuration and created all these templates, the authentication pages should now just work!</p> + +<p>You can test the new authentication pages by attempting to log in and then logout your superuser account using these URLs:</p> + +<ul> + <li><a href="http://127.0.0.1:8000/accounts/login/">http://127.0.0.1:8000/accounts/login/</a></li> + <li><a href="http://127.0.0.1:8000/accounts/logout/">http://127.0.0.1:8000/accounts/logout/</a></li> +</ul> + +<p>You'll be able to test the password reset functionality from the link in the login page. <strong>Be aware that Django will only send reset emails to addresses (users) that are already stored in its database!</strong></p> + +<div class="note"> +<p><strong>Note</strong>: The password reset system requires that your website supports email, which is beyond the scope of this article, so this part <strong>won't work yet</strong>. To allow testing, put the following line at the end of your settings.py file. This logs any emails sent to the console (so you can copy the password reset link from the console).</p> + +<pre class="brush: python notranslate">EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' +</pre> + +<p>For more information, see <a href="https://docs.djangoproject.com/en/2.0/topics/email/">Sending email</a> (Django docs).</p> +</div> + +<h2 id="authenticated_users_테스트_하기">authenticated users 테스트 하기</h2> + +<p>This section looks at what we can do to selectively control content the user sees based on whether they are logged in or not.</p> + +<h3 id="Testing_in_templates">Testing in templates</h3> + +<p>당신은 템플릿에서 <code>\{{ user }}</code> 라는 템플릿 변수로 현재 로그인한 사용자에 대한 정보를 얻을 수 있습니다 (이것은 우리의 스켈레톤을 만들때 프로젝트에서 세팅했을 때 템플릿 컨텍스트의 기본 값으로 추가된 것입니다).</p> + +<p>보통 처음으로 <code>\{{ user.is_authenticated }}</code> 라는 템플릿 변수를 통해서 당신은 사용자가 특정 내용을 볼 수 있는 지여부에 대해서 테스트하게 될 것입니다. 이를 시험하기 위해서, 우리는 사이트바에 로그인와 로그아웃 링크를 업데이트 할 것입니다.</p> + +<p>Open the base template (<strong>/locallibrary/catalog/templates/base_generic.html</strong>) and copy the following text into the <code>sidebar</code> block, immediately before the <code>endblock</code> template tag.</p> + +<pre class="brush: html notranslate"> <ul class="sidebar-nav"> + + ... + + <strong>{% if user.is_authenticated %}</strong> + <li>User: <strong>\{{ user.get_username }}</strong></li> + <li><a href="{% url 'logout'%}?next=\{{request.path}}">Logout</a></li> + <strong>{% else %}</strong> + <li><a href="{% url 'login'%}?next=\{{request.path}}">Login</a></li> + <strong>{% endif %} </strong> + </ul></pre> + +<p>As you can see, we use <code>if</code>-<code>else</code>-<code>endif</code> template tags to conditionally display text based on whether <code>\{{ user.is_authenticated }}</code> is true. If the user is authenticated then we know that we have a valid user, so we call <strong>\{{ user.get_username }} </strong>to display their name.</p> + +<p>We create the login and logout link URLs using the <code>url</code> template tag and the names of the respective URL configurations. Note also how we have appended <code>?next=\{{request.path}}</code> to the end of the URLs. What this does is add a URL parameter <font face="Consolas, Liberation Mono, Courier, monospace">next</font> containing the address (URL) of the <em>current</em> page, to the end of the linked URL. After the user has successfully logged in/out, the views will use this "<code>next</code>" value to redirect the user back to the page where they first clicked the login/logout link.</p> + +<div class="note"> +<p><strong>Note</strong>: Try it out! If you're on the home page and you click Login/Logout in the sidebar, then after the operation completes you should end up back on the same page.</p> +</div> + +<h3 id="Testing_in_views">Testing in views</h3> + +<p>If you're using function-based views, the easiest way to restrict access to your functions is to apply the <code>login_required</code> decorator to your view function, as shown below. If the user is logged in then your view code will execute as normal. If the user is not logged in, this will redirect to the login URL defined in the project settings (<code>settings.LOGIN_URL</code>), passing the current absolute path as the <code>next</code> URL parameter. If the user succeeds in logging in then they will be returned back to this page, but this time authenticated.</p> + +<pre class="brush: python notranslate">from django.contrib.auth.decorators import login_required + +@login_required +def my_view(request): + ...</pre> + +<div class="note"> +<p><strong>Note:</strong> You can do the same sort of thing manually by testing on <code>request.user.is_authenticated</code>, but the decorator is much more convenient!</p> +</div> + +<p>Similarly, the easiest way to restrict access to logged-in users in your class-based views is to derive from <code>LoginRequiredMixin</code>. You need to declare this mixin first in the superclass list, before the main view class.</p> + +<pre class="brush: python notranslate">from django.contrib.auth.mixins import LoginRequiredMixin + +class MyView(LoginRequiredMixin, View): + ...</pre> + +<p>This has exactly the same redirect behaviour as the <code>login_required</code> decorator. You can also specify an alternative location to redirect the user to if they are not authenticated (<code>login_url</code>), and a URL parameter name instead of "<code>next</code>" to insert the current absolute path (<code>redirect_field_name</code>).</p> + +<pre class="brush: python notranslate">class MyView(LoginRequiredMixin, View): + login_url = '/login/' + redirect_field_name = 'redirect_to' +</pre> + +<p>For additional detail, check out the <a href="https://docs.djangoproject.com/en/2.0/topics/auth/default/#limiting-access-to-logged-in-users">Django docs here</a>.</p> + +<h2 id="Example_—_listing_the_current_users_books">Example — listing the current user's books</h2> + +<p>Now that we know how to restrict a page to a particular user, let's create a view of the books that the current user has borrowed.</p> + +<p>Unfortunately, we don't yet have any way for users to borrow books! So before we can create the book list we'll first extend the <code>BookInstance</code> model to support the concept of borrowing and use the Django Admin application to loan a number of books to our test user.</p> + +<h3 id="Models">Models</h3> + +<p>First, we're going to have to make it possible for users to have a <code>BookInstance</code> on loan (we already have a <code>status</code> and a <code>due_back</code> date, but we don't yet have any association between this model and a User. We'll create one using a <code>ForeignKey</code> (one-to-many) field. We also need an easy mechanism to test whether a loaned book is overdue.</p> + +<p>Open <strong>catalog/models.py</strong>, and import the <code>User</code> model from <code>django.contrib.auth.models</code> (add this just below the previous import line at the top of the file, so <code>User</code> is available to subsequent code that makes use of it):</p> + +<pre class="brush: python notranslate">from django.contrib.auth.models import User +</pre> + +<p>Next, add the <code>borrower</code> field to the <code>BookInstance</code> model:</p> + +<pre class="brush: python notranslate">borrower = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True) +</pre> + +<p>While we're here, let's add a property that we can call from our templates to tell if a particular book instance is overdue. While we could calculate this in the template itself, using a <a href="https://docs.python.org/3/library/functions.html#property">property</a> as shown below will be much more efficient.</p> + +<p>Add this somewhere near the top of the file:</p> + +<pre class="brush: python notranslate">from datetime import date</pre> + +<p class="brush: python">Now add the following property definition to the <code>BookInstance</code> class:</p> + +<pre class="brush: python notranslate">@property +def is_overdue(self): + if self.due_back and date.today() > self.due_back: + return True + return False</pre> + +<div class="note"> +<p><strong>Note</strong>: We first verify whether <code>due_back</code> is empty before making a comparison. An empty <code>due_back</code> field would cause Django to throw an error instead of showing the page: empty values are not comparable. This is not something we would want our users to experience!</p> +</div> + +<p>Now that we've updated our models, we'll need to make fresh migrations on the project and then apply those migrations:</p> + +<pre class="brush: bash notranslate">python3 manage.py makemigrations +python3 manage.py migrate +</pre> + +<h3 id="Admin">Admin</h3> + +<p>Now open <strong>catalog/admin.py</strong>, and add the <code>borrower</code> field to the <code>BookInstanceAdmin</code> class in both the <code>list_display</code> and the <code>fieldsets</code> as shown below. This will make the field visible in the Admin section so that we can assign a <code>User</code> to a <code>BookInstance</code> when needed.</p> + +<pre class="brush: python notranslate">@admin.register(BookInstance) +class BookInstanceAdmin(admin.ModelAdmin): + list_display = ('book', 'status'<strong>, 'borrower'</strong>, 'due_back', 'id') + list_filter = ('status', 'due_back') + + fieldsets = ( + (None, { + 'fields': ('book','imprint', 'id') + }), + ('Availability', { + 'fields': ('status', 'due_back'<strong>,'borrower'</strong>) + }), + )</pre> + +<h3 id="Loan_a_few_books">Loan a few books</h3> + +<p>Now that its possible to loan books to a specific user, go and loan out a number of <code>BookInstance</code> records. Set their <code>borrowed</code> field to your test user, make the <code>status</code> "On loan" and set due dates both in the future and the past.</p> + +<div class="note"> +<p><strong>Note</strong>: We won't spell the process out, as you already know how to use the Admin site!</p> +</div> + +<h3 id="On_loan_view">On loan view</h3> + +<p>Now we'll add a view for getting the list of all books that have been loaned to the current user. We'll use the same generic class-based list view we're familiar with, but this time we'll also import and derive from <code>LoginRequiredMixin</code>, so that only a logged in user can call this view. We will also choose to declare a <code>template_name</code>, rather than using the default, because we may end up having a few different lists of BookInstance records, with different views and templates.</p> + +<p>Add the following to catalog/views.py:</p> + +<pre class="brush: python notranslate">from django.contrib.auth.mixins import LoginRequiredMixin + +class LoanedBooksByUserListView(LoginRequiredMixin,generic.ListView): + """Generic class-based view listing books on loan to current user.""" + model = BookInstance + template_name ='catalog/bookinstance_list_borrowed_user.html' + paginate_by = 10 + + def get_queryset(self): + return BookInstance.objects.filter(borrower=self.request.user).filter(status__exact='o').order_by('due_back')</pre> + +<p>In order to restrict our query to just the <code>BookInstance</code> objects for the current user, we re-implement <code>get_queryset()</code> as shown above. Note that "o" is the stored code for "on loan" and we order by the <code>due_back</code> date so that the oldest items are displayed first.</p> + +<h3 id="URL_conf_for_on_loan_books">URL conf for on loan books</h3> + +<p>Now open <strong>/catalog/urls.py</strong> and add a<code>path()</code> pointing to the above view (you can just copy the text below to the end of the file).</p> + +<pre class="brush: python notranslate">urlpatterns += [ + path('mybooks/', views.LoanedBooksByUserListView.as_view(), name='my-borrowed'), +]</pre> + +<h3 id="Template_for_on-loan_books">Template for on-loan books</h3> + +<p>Now, all we need to do for this page is add a template. First, create the template file <strong>/catalog/templates/catalog/bookinstance_list_borrowed_user.html</strong> and give it the following contents:</p> + +<pre class="brush: python notranslate">{% extends "base_generic.html" %} + +{% block content %} + <h1>Borrowed books</h1> + + {% if bookinstance_list %} + <ul> + + {% for bookinst in bookinstance_list %} + <li class="{% if bookinst.is_overdue %}text-danger{% endif %}"> + <a href="{% url 'book-detail' bookinst.book.pk %}">\{{bookinst.book.title}}</a> (\{{ bookinst.due_back }}) + </li> + {% endfor %} + </ul> + + {% else %} + <p>There are no books borrowed.</p> + {% endif %} +{% endblock %}</pre> + +<p>This template is very similar to those we've created previously for the <code>Book</code> and <code>Author</code> objects. The only thing "new" here is that we check the method we added in the model <code>(bookinst.is_overdue</code>) and use it to change the colour of overdue items.</p> + +<p>When the development server is running, you should now be able to view the list for a logged in user in your browser at <a href="http://127.0.0.1:8000/catalog/mybooks/">http://127.0.0.1:8000/catalog/mybooks/</a>. Try this out with your user logged in and logged out (in the second case, you should be redirected to the login page).</p> + +<h3 id="Add_the_list_to_the_sidebar">Add the list to the sidebar</h3> + +<p>The very last step is to add a link for this new page into the sidebar. We'll put this in the same section where we display other information for the logged in user.</p> + +<p>Open the base template (<strong>/locallibrary/catalog/templates/base_generic.html</strong>) and add the line in bold to the sidebar as shown.</p> + +<pre class="brush: python notranslate"> <ul class="sidebar-nav"> + {% if user.is_authenticated %} + <li>User: \{{ user.get_username }}</li> +<strong> <li><a href="{% url 'my-borrowed' %}">My Borrowed</a></li></strong> + <li><a href="{% url 'logout'%}?next=\{{request.path}}">Logout</a></li> + {% else %} + <li><a href="{% url 'login'%}?next=\{{request.path}}">Login</a></li> + {% endif %} + </ul> +</pre> + +<h3 id="What_does_it_look_like">What does it look like?</h3> + +<p>When any user is logged in, they'll see the <em>My Borrowed</em> link in the sidebar, and the list of books displayed as below (the first book has no due date, which is a bug we hope to fix in a later tutorial!).</p> + +<p><img alt="Library - borrowed books by user" src="https://mdn.mozillademos.org/files/14105/library_borrowed_by_user.png" style="border-style: solid; border-width: 1px; display: block; height: 215px; margin: 0px auto; width: 530px;"></p> + +<h2 id="허가">허가</h2> + +<p>Permissions 는 모델과 연관되어 허가를 가진 유저에 의한 model instance 작업들을 정의하게 됩니다. 기본적으로 Django 자동적으로 <em>add</em>, <em>change</em>, 그리고 <em>delete</em> permissions 을 모든 모델에 제공하는데, 유저가 관리자 사이트를 통해서 (권한)허가를 가지고 연고나도니 작업들을 하게 합니다. 당신은 권한을 모델이나 특정 유저에게 부여하도록 정의할 수 있습니다. You can also change the permissions associated with different instances of the same model.</p> + +<p>Testing on permissions in views and templates is then very similar for testing on the authentication status (and in fact, testing for a permission also tests for authentication).</p> + +<h3 id="Models_2">Models</h3> + +<p>Defining permissions is done on the model "<code>class Meta</code>" section, using the <code>permissions</code> field. You can specify as many permissions as you need in a tuple, each permission itself being defined in a nested tuple containing the permission name and permission display value. For example, we might define a permission to allow a user to mark that a book has been returned as shown:</p> + +<pre class="brush: python notranslate">class BookInstance(models.Model): + ... + class Meta: + ... +<strong> permissions = (("can_mark_returned", "Set book as returned"),) </strong> </pre> + +<p>We could then assign the permission to a "Librarian" group in the Admin site.</p> + +<p>Open the <strong>catalog/models.py</strong>, and add the permission as shown above. You will need to re-run your migrations (call <code>python3 manage.py makemigrations</code> and <code>python3 manage.py migrate</code>) to update the database appropriately.</p> + +<h3 id="Templates">Templates</h3> + +<p>The current user's permissions are stored in a template variable called <code>\{{ perms }}</code>. You can check whether the current user has a particular permission using the specific variable name within the associated Django "app" — e.g. <code>\{{ perms.catalog.can_mark_returned }}</code> will be <code>True</code> if the user has this permission, and <code>False</code> otherwise. We typically test for the permission using the template <code>{% if %}</code> tag as shown:</p> + +<pre class="brush: python notranslate">{% if perms.catalog.<code>can_mark_returned</code> %} + <!-- We can mark a BookInstance as returned. --> + <!-- Perhaps add code to link to a "book return" view here. --> +{% endif %} +</pre> + +<h3 id="Views">Views</h3> + +<p>Permissions can be tested in function view using the <code>permission_required</code> decorator or in a class-based view using the <code>PermissionRequiredMixin</code>. The pattern and behaviour are the same as for login authentication, though of course, you might reasonably have to add multiple permissions.</p> + +<p>Function view decorator:</p> + +<pre class="brush: python notranslate">from django.contrib.auth.decorators import permission_required + +@permission_required('catalog.<code>can_mark_returned</code>') +@permission_required('catalog.<code>can_edit</code>') +def my_view(request): + ...</pre> + +<p>A permission-required mixin for class-based views.</p> + +<pre class="brush: python notranslate">from django.contrib.auth.mixins import PermissionRequiredMixin + +class MyView(PermissionRequiredMixin, View): + permission_required = 'catalog.<code>can_mark_returned</code>' + # Or multiple permissions + permission_required = ('catalog.<code>can_mark_returned</code>', 'catalog.can_edit') + # Note that 'catalog.can_edit' is just an example + # the catalog application doesn't have such permission!</pre> + +<h3 id="Example">Example</h3> + +<p>We won't update the <em>LocalLibrary</em> here; perhaps in the next tutorial!</p> + +<h2 id="Challenge_yourself">Challenge yourself</h2> + +<p>Earlier in this article, we showed you how to create a page for the current user listing the books that they have borrowed. The challenge now is to create a similar page that is only visible for librarians, that displays <em>all</em> books that have been borrowed, and which includes the name of each borrower.</p> + +<p>You should be able to follow the same pattern as for the other view. The main difference is that you'll need to restrict the view to only librarians. You could do this based on whether the user is a staff member (function decorator: <code>staff_member_required</code>, template variable: <code>user.is_staff</code>) but we recommend that you instead use the <code>can_mark_returned</code> permission and <code>PermissionRequiredMixin</code>, as described in the previous section.</p> + +<div class="warning"> +<p><strong>Important</strong>: Remember not to use your superuser for permissions based testing (permission checks always return true for superusers, even if a permission has not yet been defined!). Instead, create a librarian user, and add the required capability.</p> +</div> + +<p>When you are finished, your page should look something like the screenshot below.</p> + +<p><img alt="All borrowed books, restricted to librarian" src="https://mdn.mozillademos.org/files/14115/library_borrowed_all.png" style="border-style: solid; border-width: 1px; display: block; height: 283px; margin: 0px auto; width: 500px;"></p> + +<ul> +</ul> + +<h2 id="Summary">Summary</h2> + +<p>Excellent work — you've now created a website that library members can log in into and view their own content and that librarians (with the correct permission) can use to view all loaned books and their borrowers. At the moment we're still just viewing content, but the same principles and techniques are used when you want to start modifying and adding data.</p> + +<p>In our next article, we'll look at how you can use Django forms to collect user input, and then start modifying some of our stored data.</p> + +<h2 id="See_also">See also</h2> + +<ul> + <li><a href="https://docs.djangoproject.com/en/2.0/topics/auth/">User authentication in Django</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.0/topics/auth/default//">Using the (default) Django authentication system</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.0/topics/class-based-views/intro/#decorating-class-based-views">Introduction to class-based views > Decorating class-based views</a> (Django docs)</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Django/Sessions", "Learn/Server-side/Django/Forms", "Learn/Server-side/Django")}}</p> + + + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Server-side/Django/Introduction">Django introduction</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/development_environment">Setting up a Django development environment</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Django Tutorial: The Local Library website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django Tutorial Part 2: Creating a skeleton website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Models">Django Tutorial Part 3: Using models</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Admin_site">Django Tutorial Part 4: Django admin site</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django Tutorial Part 5: Creating our home page</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Generic_views">Django Tutorial Part 6: Generic list and detail views</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Sessions">Django Tutorial Part 7: Sessions framework</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Authentication">Django Tutorial Part 8: User authentication and permissions</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Forms">Django Tutorial Part 9: Working with forms</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Testing">Django Tutorial Part 10: Testing a Django web application</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Django Tutorial Part 11: Deploying Django to production</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/web_application_security">Django web application security</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></li> +</ul> diff --git a/files/ko/learn/server-side/django/deployment/index.html b/files/ko/learn/server-side/django/deployment/index.html new file mode 100644 index 0000000000..9ea3f870e5 --- /dev/null +++ b/files/ko/learn/server-side/django/deployment/index.html @@ -0,0 +1,685 @@ +--- +title: 'Django 튜토리얼 파트 11: Django 웹사이트 공개하기' +slug: Learn/Server-side/Django/Deployment +tags: + - Django deployment + - django + - heroku + - whitenoise + - 웹 서버 + - 장고 + - 장고 배포 +translation_of: Learn/Server-side/Django/Deployment +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Django/Testing", "Learn/Server-side/Django/web_application_security", "Learn/Server-side/Django")}}</div> + +<p class="summary">당신은 이제 놀라운 <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a> 웹사이트를 (테스트도 마치고) 만들었으니, 도서관 스태프나 회원들이 인터넷을 통해 이용할 수 있도록 공개된 웹 서버에 설치하길 원할 것이다. 이번 장에서는 웹사이트를 배포할수 있는 호스트를 살펴보는 방법에 대한 개요와 사이트를 실제 운운영하기위해 필요한 것들에 대해 설명한다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">사전학습:</th> + <td>아래 파트를 포함하여 앞선 모든 튜토리얼 파트의 학습을 완료할 것. <a href="/en-US/docs/Learn/Server-side/Django/Testing">Django 튜토리얼 파트 10: Django 웹 어플리케이션 테스트하기</a></td> + </tr> + <tr> + <th scope="row">학습목표:</th> + <td>Django 앱을 공개 운영할 수 있는 네트워크상의 장소와 방법을 배우기.</td> + </tr> + </tbody> +</table> + +<h2 id="개요">개요</h2> + +<p>일단 사이트 개발이 완료되면( 혹은 공개 테스트를 시작할 정도로 "충분히" 완료되었다면 ) 개인 컴퓨터 환경보다는 좀더 공개되고 접근성이 있는 네트워크상의 장소가 필요할 것이다.</p> + +<p>이제까지는, Django 개발용 웹 서버를 사용하여 사이트를 로컬 브라우저/네트워크 범위 내에서 공개하고, 암호를 포함한 개인정보및 디버깅정보가 노출되는 (보안이 부실한) 개발용 환경 설정으로 웹사이트를 실행하면서, 개발환경에서만 작업을 해왔다. 외부에서 웹사이트를 운영하기 전에 해야할 일은 다음과 같다:</p> + +<ul> + <li>프로젝트 설정에서 몇가지를 고쳐야 한다.</li> + <li>Django 앱을 호스팅할 환경을 선택해야 한다.</li> + <li>정적 파일들(static files)을 호스팅할 환경을 선택해야 한다.</li> + <li>웹 사이트를 서비스할 공개단계 레벨의 기반환경을 구축한다.</li> +</ul> + +<p>이 튜토리얼은 호스팅사이트를 선택하기위한 몇가지 지침과 Django 앱을 공개하는데 대비하기 위해 필요한 사항에 대한 간단한 개요및 LocalLibrary 웹사이트를 <a href="https://www.heroku.com/">Heroku</a> 클라우드 호스팅 서비스 위에서 운영되도록 설치하는 방법에 대해 동작하는 예제를 제공한다.</p> + +<h2 id="운영환경_(Production_envrionment)_이란">운영환경 (Production envrionment) 이란?</h2> + +<p>운영환경은 외부공개를 위한 웹사이트를 운영하는 서버 컴퓨터로 부터 제공되는 환경이다. 운영환경은 다음 요소로 구성된다 :</p> + +<ul> + <li>웹사이트가 실행되는 컴퓨터 하드웨어.</li> + <li>Linux, Windows와 같은 운영체제.</li> + <li>웹 사이트를 작성한 프로그래밍 언어 구동 환경(runtime)과 프레임웍 라이브러리.</li> + <li>콘텐츠및 페이지를 서비스 하기위한 Nginx, Apache와 같은 웹 서버.</li> + <li>Django 웹사이트와 웹서버간에 "동적인" request 를 전달하기위한 어플리케이션 서버.</li> + <li>웹사이트의 정보를 저장하는 데이타베이스.</li> +</ul> + +<div class="note"> +<p><strong>주목할점</strong>: 운영환경의 설정에 따라 역방향 프록시(reverse proxy)나 로드 밸런서(load balancer)등이 추가될 수도 있다.</p> +</div> + +<p>서버 컴퓨터는 빠른 인터넷으로 연결되어 당신의 사무실내에 위치할 수도 있지만, 보통 "클라우드 상에서" 사용하는것이 훨씬 더 흔한 방법이다. 이말은 실제로는 당신의 코드가 호스팅 업체의 데이터센터에 위치한 어떤 원격 컴퓨터에서(혹은 아마도 "가상환경의" 컴퓨터상에서) 실행된다는 것을 의미한다. 원격지 서버는 대개는 어느 정도 검증된 수준의 컴퓨터 자원(예를들면, CPU, 램, 저장 메모리 공간등)과 가격대별 인터넷 연결을 제공한다.</p> + +<p>이런 종류의 원격 접속가능한 컴퓨터/네트워크 하드웨어를 IaaS ( <em>Infrastructure as a Service) 라고 줄여 부른다</em>. 많은 IaaS 업체들은 미리 설치된 특정 OS 환경에 대한 여러가지 옵션을 제공하는데 당신은 그 위에 운영환경에 필요한 것들을 설치해야 한다. 또 다른 업체는 장고와 웹서버등을 포함하여 완전히 갖추어진 환경을 선택할수 있도록 옵션을 제공하기도 한다.</p> + +<div class="note"> +<p><strong>주목할점:</strong> 미리 구성된 환경에서는 환경설정에 대한 부담을 덜 수 있어서 웹사이트 구성을 매우 쉽게할 수 있지만, 익숙하지 않은 서버환경이나 다른 콤포넌트 때문에, 혹은 구형 OS 버전 때문에 선택가능한 구성수단이 줄어들 수도 있다. 많은 경우에, 당신이 원하는 결과를 얻기 위해, 당신이 직접 필요한 콤포넌트를 설치하는 것이 낫다. 그러면 시스템 업그레이드가 필요한 경우에, 어떻게 시작해야 하는지 알아챌 수 있을 것이다 !</p> +</div> + +<p>다른 호스팅 업체들은 Django를 플랫폼의 일부분으로 지원하는데 이런 업체를 PaaS( <em>Platform as a Service)로 줄여 부른다</em>. 이런 종류의 호스팅에서는 호스트 플랫폼이 (어플리케이션의 규모의 변화에 따라 조정해야하는 거의 모든 것을 포함하여) 대신 관리해주므로 운영환경(웹 서버, 어플리케이션 서버, 로드 밸런서등)에 대해 거의 고민할 필요가 없다. 이 경우, 다른 서버 기반환경에 신경쓸 필요없이, 웹 어플리케이션에만 집중할수 있기 때문에 웹사이트 배포가 엄청 쉽다.</p> + +<p>어떤 개발자들은 PaaS에 비해 좀더 높은 자유도를 가진 IaaS를 선택하는 반면, 다른 개발자들은 관리부담이 덜하고 웹사이트 규모를 쉽게 조정할수 있는 PaaS를 선택할 것이다. 당신은 이제 막 개발을 시작했기에, PaaS에 웹사이트를 설정하는 것이 더 쉬울 것이다. 그리고 그것이 이 튜토리얼에서 우리가 공부할 내용이다.</p> + +<div class="note"> +<p><strong>한가지 팁:</strong> Python/Django 친화적인 호스팅 업체를 선정했다면, 웹서버,어플리케이션 서버, 역방향 프록시( 혹시 PaaS 업체를 선정했다면 별로 신경쓸 필요없는 내용임)의 여러가지 설정을 이용한 Django 웹사이트를 구성하는 방법에 대한 설명이 제공될 것이다. 예를 들면, 이곳 ( <a href="https://www.digitalocean.com/community/tutorials?q=django">Digital Ocean Django community docs</a> ) 에는 다양한 설정에 대한 단계적인 가이드가 있다.</p> +</div> + +<h2 id="호스팅_업체_선정하기">호스팅 업체 선정하기</h2> + +<p>Django에 대한 지원이 활발하게 이루어지거나 Django가 잘 동작한다고 알려진 호스팅 업체는 약 100여곳이 있다. ( 꽤 광범위한 목록을 <a href="http://djangofriendly.com/hosts/">Djangofriendly hosts</a> 에서 찾아볼 수 있다.) 이 업체들은 서로 다른 타입(IaaS, PaaS)이거나 서로 다른 가격대에 여러가지 수준의 컴퓨팅/네트워크 자원을 제공한다.</p> + +<p>호스팅 업체를 선정할 때 고려해야할 몇가지는 다음과 같다:</p> + +<ul> + <li>당신의 사이트가 얼마나 바쁘게 돌아갈 것인지와 이 요구조건을 감당할수 있는 데이터와 컴퓨팅 자원의 비용 수준.</li> + <li>수평적인(같은 머신을 더 많이 사용하기) 혹은 수직적인(좀더 고성능의 머신을 사용하기) 사이트 규모조정 수준과 이 작업에 필요한 비용.</li> + <li>공급자의 데이터 센터가 위치한 장소와 그에 따른 가장 빠르게 접속할 수 있는 장소.</li> + <li>호스트의 역대 가동시간및 가동중지시간 상의 성능.</li> + <li>사이트 관리용으로 제공되는 도구 - 가 사용하기 쉬운지와 안전한지 ( 예를들면 SFTP vs FTP )</li> + <li>당신의 서버를 모니터링 하기위하 내장 프레임워크.</li> + <li>알려진 제한사항들. 어떤 호스트 업체는 의도적 특정 서비스(예를 들면 email)를 제한한다. 또 다른 업체는 특정 가격대에 일정 시간의 "가동시간"이나 일정량의 저장공간만을 제공한다.</li> + <li>추가적인 혜택들. 어떤 업체들은 다른곳에서는 유료로 지원되는 도메인 네임과 SSL인증에 대한 지원을 무료로 제공한다. </li> + <li>당신이 사용하던 "무료"계정이 시간초과로 중지되거나 좀더 비싼 계정으로 이전하는데 비용들거나 하게된다는 것은 처음에 선택한 호스팅 서비스와 다른 선택을 했다면 웹사이트가 좀더 성공적일 수도 있었다는 것을 의미한다! </li> +</ul> + +<p>당신이 개발을 시작했다면 좋은 소식은 "평가용", "개발자용"혹은 "취미개발용" 컴퓨터 환경을 "무료"로 제공하는 업체가 꽤 있다는 것이다. 이들은 항상 자원을 아주 제한적으로만 사용할 수 있고, 처음 신규 가입 기간이 지나 중지되지 않는지 주의를 기울여야 한다. 하지만, 트래픽이 낮은 사이트를 실제 운영환경에서 테스트 하기에 좋으며, 사이트가 좀더 바빠질 경우 더 많은 자원을 제공하는 유료환경으로 쉽게 이전할 수 있다.이런 종류의 환경으로 인기있는 곳은 <a href="https://www.heroku.com/">Heroku</a>, <a href="https://www.pythonanywhere.com/">Python Anywhere</a>, <a href="http://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/billing-free-tier.html">Amazon Web Services</a>, <a href="https://azure.microsoft.com/en-us/pricing/details/app-service/">Microsoft Azure</a> 등등이다.</p> + +<p>많은 업체가 좀더 쓸만한 수준의 컴퓨팅 파워와 제한사항을 완화한 "기본"계정을 가지고 있다. <a href="https://www.digitalocean.com/">Digital Ocean</a> 과 <a href="https://www.pythonanywhere.com/">Python Anywhere</a> 는 상대적으로 비용이 낮은( 1달에 5~10 USD 가격의) 기본 계정을 제공하는 인기있는 호스팅 업체의 대표적인 예이다.</p> + +<div class="note"> +<p><strong>주목할점:</strong> 사용가격이 유일한 선택기준이 아니라는 것을 명심하라. 당신의 웹사이트가 성공적이라면 사이트의 확장성이 가장 중요한 기준이 될것이다.</p> +</div> + +<h2 id="웹사이트에서_공개(publish)준비_하기">웹사이트에서 공개(publish)준비 하기</h2> + +<p>django-admin과 manage.py 도구로 생성된 <a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django 뼈대 웹사이트</a>는 개발환경에 최적화 되어 설정되었다. 개발환경이 아닌 운영환경에서는 ( <strong>settings.py</strong>에 설정되어 있는 ) Django 프로젝트 설정의 많은 부분이, 보안상 혹은 성능상 이유로, 변경되어야 한다.</p> + +<div class="note"> +<p><strong>한가지 팁:</strong> 운영환경용으로 별도의 <strong>settings.py</strong> 파일을 유지하고 민감한 설정들은 별도의 파일이나 시스템의 환경변수에 저장하는 것이 일반적이다. 소스코드의 다른 부분은 공개된 저장소에 보관하더라도, 이 파일은 격리되어 보호되어야 한다. </p> +</div> + +<p>반드시 체크되어야 할 가장 중요한 설정은 다음과 같다 :</p> + +<ul> + <li><code>DEBUG</code>. 이 설정은 운영환경에서 <code>False</code> 로 설정되어야 한다 (<code>DEBUG = False</code>). 이 설정은 민감하고 / 보호가 필요한 디버그 정보나 변수정보가 외부로 보여지지 않도록 막는다.</li> + <li><code>SECRET_KEY</code>. CRSF 보안등을 위해 사용되는 큰 숫자의 랜덤 값이다. 운영환경에서 사용되는 key 값이 형상관리툴에 등록되지 않도록 하거나 운영 서버 밖에서 접근할 수 없도록 관리하는 것이 중요하다. Django 문서에서는 이 값을 환경 변수에서 로딩하거나 serve-only 파일에서 읽어오도록 제안하고 있다. + <pre># Read SECRET_KEY from an environment variable +import os +SECRET_KEY = os.environ['SECRET_KEY'] + +#OR + +#Read secret key from a file +with open('/etc/secret_key.txt') as f: + SECRET_KEY = f.read().strip()</pre> + </li> +</ul> + +<p><em> </em><code>SECRET_KEY</code><em> 와 </em><code>DEBUG</code><em> 변수를, 이 변수들이 정의되어 있다면, 시스템의 환경 변수에서 읽어오도록 LocalLibrary</em> 어플리케이션을 수정하자. 정의되어 있지 않다면 설정 파일의 디폴트 값을 사용하도록 한다.</p> + +<p><strong>/locallibrary/settings.py</strong> 파일을 열고, 기존의 <code>SECRET_KEY</code> 설정을 비활성화 하고 아래 코드에서 <strong>bold</strong>체로 보이는 부분을 추가한다. 개발 과정중에는 보통 key와 관련하여 환경변수가 설정되지 않으므로 초기값이 사용되고 있을것이다. ( 키가 노출되면 당신이 그 키를 운영환경에 사용하지는 않을것이므로 여기서 어떤키를 사용하는지는 중요하지 않다).</p> + +<pre class="brush: python"># SECURITY WARNING: keep the secret key used in production secret! +# SECRET_KEY = 'cg#p$g+j9tax!#a3cup@1$8obt2_+&k3q+pmu)5%asj6yjpkag' +<strong>import os</strong> +<strong>SECRET_KEY = os.environ.get('DJANGO_SECRET_KEY', 'cg#p$g+j9tax!#a3cup@1$8obt2_+&k3q+pmu)5%asj6yjpkag')</strong> +</pre> + +<p>그리고나서 기존의 <code>DEBUG</code> 설정을 주석처리 하고 신규 라인을 아래와 같이 추가 하라.</p> + +<pre class="brush: python"># SECURITY WARNING: don't run with debug turned on in production! +# DEBUG = True +<strong>DEBUG = bool( os.environ.get('DJANGO_DEBUG', True) )</strong> +</pre> + +<p><code>DEBUG</code> 의 초기값은 <code>True</code> 이지만, <code>DJANGO_DEBUG</code> 환경변수가 비어있는 문자열로 설정 되면 (즉, <code>DJANGO_DEBUG=''</code> 와 같이) <code>False</code> 로 설정될 것이다.</p> + +<div class="note"> +<p><strong>주목할 점</strong>: <code>DJANGO_DEBUG</code> 환경변수를 "값을 가진 문자열"이나 "빈 문자열" 로 설정하기 보다, 그냥 <code>True</code> 나 <code>False</code> 로 (각각) 직접 설정할 수 있다면 이런 방식이 좀더 직관적으로 보일것이다. 하지만 불행히도 환경변수는 파이썬 문자열로 저장되며, <code>False</code> 로 평가받을수 있는 문자열은 "빈 문자열"이 유일하다.</p> + +<p>역자주: os.environ.get의 사용법에 대해서는 이 <a href="https://bugs.python.org/msg277165">링크</a>를 참조 하라</p> +</div> + +<p>변경해야할 설정의 전체 체크리스트는 <a href="https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/">배포 체크리스트</a> (장고 문서) 로 제공된다. 아래 터미널 명령으로도 몇몇 목록을 뽑을 수 있다:</p> + +<pre class="brush: python">python3 manage.py check --deploy +</pre> + +<h2 id="예제_LocalLibrary를_Heroku에_설치하기">예제: LocalLibrary를 Heroku에 설치하기</h2> + +<p>이번 섹션에서는 <a href="http://heroku.com">Heroku PaaS 클라우드</a> 에 LocalLibrary를 설치하는 방법에 대한 실제적인 예제를 제공한다.</p> + +<h3 id="왜_Heroku_인가">왜 Heroku 인가?</h3> + +<p>Heroku는 현재까지 가장 오래 운영된 서비스들중 하나이며, 인기있는 클라우드기반 PaaS 서비스이다. 원래는 Ruby 앱들만 지원했지만, 현재는 많은 프로그래밍 환경의 앱들을 지원할수 있으며, 여기에는 Django 또한 포함된다!</p> + +<p>우리는 다음과 같은 이유로 Heroku 를 사용하기로 결정했다:</p> + +<ul> + <li>Heroku는 정말 돈 낼 필요가 없는 <a href="https://www.heroku.com/pricing">무료 단계 (free tier)</a> 를 지원한다. (물론 약간의 제약이 있긴하다).</li> + <li>Heroku는 PaaS 개념의 서비스로 많은 웹 기반환경의 관리를 제공한다. 서버관리, 로드 밸런싱, 역방향 프록시등 여러가지 웹 기반환경들을 Heroku가 내부적으로 모두 제공하므로 이에 대한 걱정을 덜고 쉽게 개발을 시작할수 있다.</li> + <li>제약이 있긴하지만, 이 제약들은 우리가 진행하려는 어플리케이션 개발에는 영향이 없을 것이다. 예를 들면 다음과 같다: + <ul> + <li>무료 단계의 Heroku는 활성주기가 짧은 저장공간을 제공하므로 유저가 업로드한 파일을 Heroku 자체에 안전하게 저장할 수는 없다.</li> + <li>무료 단계에서는 30분동안 아무런 요청도 없다면 웹 앱은 비활성화 될 것이다. 이 후에 요청이 오면 응답하는데 몇 초정도 약간의 시간이 더 필요하게 될것이다. </li> + <li>무료 단계에서는 웹 사이트의 동작 가능 시간이 매월 특정시간 만큼으로 제한된다 ( 사이트가 "비활성(asleep)"상태인 경우의 시간은 제외된다). 이 제약은 사용빈도가 낮고/ 예제 확인용 사이트인 경우는 문제가 되지 않지만, 계속 활성화 상태가 필요한 앱의 경우에는 적합하지 않을것이다.</li> + <li>다른 제약 사항은 <a href="https://devcenter.heroku.com/articles/limits">Limits</a> (Heroku 문서) 에서 찾아볼 수 있다.</li> + </ul> + </li> + <li>대부분의 경우 문제없이 사용할 수 있을것이고, 당신이 결국 Heroku에 만족하게 되었다면, 당신의 앱을 확장하는 것도 매우 쉽다.</li> +</ul> + +<p>Heroku로 이 예제를 호스팅 하는데는 부족함이 없겠지만, 당신이 개발하고자 하는 실제 웹사이트의 요구조건에는 부족할 수도 있다. Heroku는 설치하여 사용하고 확장하기는 쉽지만 대신 모든 요구조건을 충족할 정도로 유연하지는 않으며 일단 무료 단계를 벗어나면 당신의 요구조건을 만족시키기 위해 좀더 비싼 비용을 요구할 가능성이 잠재되어있다.</p> + +<h3 id="Heroku는_어떻게_동작하는가">Heroku는 어떻게 동작하는가?</h3> + +<p>Heroku는 Django 웹사이트를 한 개이상의 "<a href="https://devcenter.heroku.com/articles/dynos">다이노(Dyno</a>)"에서 실행한다. 다이노란 고립적이고, 가상화된 Unix 콘테이너이며 어플리케이션을 실행하는데 필요한 환경을 제공한다. 다이노는 완전히 고립적이며 <em>ephemeral </em>( <em>다이노가 재시작될 때마다 깨끗이 비워지는 단기 수명의 )</em> 파일 시스템을 가지고 있다. 다이노간에 공유하는 유일한 항목은 어플리케이션 <a href="https://devcenter.heroku.com/articles/config-vars">설정 변수</a> 이다. Heroku 는 웹 트래픽을 모든 "웹" 다이노들로 분배하기 위해 내부적으로 로드 밸런서를 사용한다. 다이노들간에 공유하는것이 없기때문에 Heroku는 단지 다이노를 좀더 추가하는 것으로 앱을 수평적으로 확장할 수있다. ( 사실은 당연히 추가적인 접속자를 받기위해 다이노 뿐만 아니라 데이타베이스도 확장할 필요가 있긴 하다).</p> + +<p>파일 시스템이 단기 수명의 특성이 있어서, 어플리케이션에 필요한 서비스(즉, 데이타베이스, 큐, 캐싱 시스템, 저장공간, 이메일 서비스 등등) 를 직접 설치할 수는 없다. 대신에 Heroku 웹 어플리케이션들은 Heroku나 써드파티로 부터 제공되는 독립적인 "애드온"들로 부터의 지원 서비스를 이용한다. 일단 애드온이 웹 어플리케이션에 부착되면, 다이노는 어플리케이션 설정 변수에 포함된 정보를 사용하여 서비스에 접속한다. </p> + +<p>어플리케이션을 실행하기위해서, Heroku는 적절한 환경과 의존성을 셋업하고 어떻게 런칭되는지 이해할 필요가 있다. Django 앱에 대해서는 아래 정보를 몇개의 텍스트 파일로 제공한다.</p> + +<ul> + <li><strong>runtime.txt</strong>:<strong> </strong>프로그래밍 언어와 사용 버전.</li> + <li><strong>requirements.txt</strong>: Django를 포함한 파이썬 관련 라이브러리 의존성.</li> + <li><strong>Procfile</strong>: 웹 어플리케이션을 구동하기 위해 실행되어야 하는 프로세스의 목록. 장고의 예를 들자면, Gunicorn 웹 어플리케이션 서버( .wsgi 스크립트와 함께) 가 될것이다. </li> + <li><strong>wsgi.py</strong>: Heroku 환경에서 Django 어플리케이션을 호출 하기 위한 <a href="http://wsgi.readthedocs.io/en/latest/what.html">WSGI</a> 설정.</li> +</ul> + +<p>개발자들은 Unix bash 스크립트와 매우 유사한, 특별한 클라이언트 앱/터미널로 Heroku와 통신한다. 이 도구는 git 저장소에 보관된 코드를 업로드 할수 있도록 지원하며, 실행중인 프로세스의 모니터링과, 로그를 보고 환경변수를 설정하는등 그외 많은 일을 할수 있도록 지원한다!</p> + +<p>Heroku 상에서 어플리케이션을 실행하기 위해서는 Django 웹 어플리케이션을 git 저장소에 보관하고, 위에서 언급한 파일을 추가하며, 데이터베이스 애드온과 통합하고, 스태틱 파일을 다룰수 있도록 수정할 필요가 있다.</p> + +<p>일단 Heroku 계정에서 준비할수 있는 모든것을 완료 했으니, Heroku 클라이언트를 다운로드 받아서 웹 사이트를 설치하라.</p> + +<div class="note"> +<p><strong>주목할 점:</strong> 아래 지시사항은 이 글을 쓸 당시의 Heroku로 작업하는 방법을 반영했다. Heroku 서비스의 절차가 상당히 많이 바뀐다면, 이글 대신 다음링크의 Heroku 문서를 참조하는 것이 좋다: <a href="https://devcenter.heroku.com/articles/getting-started-with-python#introduction">Django로 Heroku 시작하기</a>.</p> +</div> + +<p>이것으로 시작을 하기위한 준비를 모두 마친다. ( 좀 더 포괄적인 이해를 위해서는 <a href="https://devcenter.heroku.com/articles/how-heroku-works">Heroku의 동작 방식</a>(Heroku 문서) 가이드를 참고하라).</p> + +<h3 id="Github에_애플리케이션_저장소(repository)_생성하기"> Github에 애플리케이션 저장소(repository) 생성하기</h3> + +<p>Heroku는 <strong>git</strong> 형상관리 시스템과 밀접하게 통합되어있는데, git을 이용하여 활성화된 시스템에 수정사항의 업로드및 동기화를 수행한다. git은 Heroku 클라우드 상에서 당신의 소스코드 저장소를 가리키도록 이름붙여진 신규 heroku "원격" 저장소를 추가함으로 이 작업을 수행한다. 개발기간동안 "master" 저장소에 변경사항을 저장하기 위에 git을 사용하게된다. 사이트를 배포할 때가 되면, Heroku 저장소에 수정사항을 동기화 한다.</p> + +<div class="note"> +<p><strong>주목할 점:</strong> 좋은 소프트웨어 개발 예제를 따라서 작성하는데 익숙하다면, 아마도 당신은 이미 git 이나 다른 SCM 도구를 사용하고 있을 것이다. 당신이 이미 git 저장소를 소유하고 있다면, 이 단계를 건너뛰어도 좋다.</p> +</div> + +<p>git 으로 작업하는 수많은 방법이 있지만, <a href="https://github.com/">Github</a>에 계정을 생성하여, 저장소를 생성하고, 로컬 컴퓨터와 동기화 하는것이 가장 쉬운 방법중 하나이다 :</p> + +<ol> + <li>이곳( <a href="https://github.com/">https://github.com/</a> )을 방문하여 계정을 생성하라.</li> + <li>로그인 해서 꼭대기 툴바의 <strong>+</strong> 링크를 클릭하여 <strong>New repository</strong>를 선택하라.</li> + <li>이 폼의 모든 필드에 기입하라. 그렇지 않으면 진행이 불가한 것은 아니지만, 모두 채울것을 강력 추천한다. + <ul> + <li>새로운 저장소 이름 (예시: <em>django_local_library</em>)과 설명 (예시: "Local Library website written in Django")을 입력하라.</li> + <li>"<em>Add .gitignore" 선택 목록에서 "</em><strong>Python</strong><em>"을 선택하라</em>.</li> + <li>"<em>Add a license" 선택 목록에서 선호하는 라이센스 유형을 선택하라</em>.</li> + <li>"<strong>Initialize this repository with a README</strong>." 체크박스에 체크하라</li> + </ul> + </li> + <li>" <strong>Create repository" </strong>버튼을 누른다</li> + <li>신규 저장소 페이지에서 초록색의 "<strong>Clone or download</strong>" 버튼을 클릭한다.</li> + <li>아래와 같은 형태의 URL 값을 다이얼로그 박스내의 텍스트 필드에서 복사한다.(예시: <strong>https://github.com/<em><your_git_user_id></em>/django_local_library.git</strong>).</li> +</ol> + +<p>이제 원격 저장소 ("repo")가 생성되었으니 로컬 컴퓨터에 복제(clone)하길 원할 것이다:</p> + +<ol> + <li><em>git을 로컬 컴퓨터에 설치하라</em> (플랫폼별 버전은 <a href="https://git-scm.com/downloads">이곳</a> 에서 찾을 수 있다).</li> + <li>커맨드 프롬프트/터미널 을 열고 위에서 복사한 URL을 이용하여 저장소 내용을 복제(clone) 한다 : + <pre class="brush: bash">git clone https://github.com/<strong><em><your_git_user_id></em></strong>/django_local_library.git +</pre> + 이 명령은 현재 프롬프트의 위치에 저장소를 생성할 것이다.</li> + <li>새로운 저장소 위치로 이동한다. + <pre class="brush: bash">cd django_local_library.git</pre> + </li> +</ol> + +<p>마지막 단계는 어플리케이션을 복사하여 git을 이용해 저장소에 파일을 추가하는 것이다 :</p> + +<ol> + <li>이 폴더에 Django 어플리케이션을 복사해 넣는다. (locallibrary 폴더를 포함한 위치가 아니라 <strong>manage.py</strong> 와 그 하위 폴더와 같은 위치의 모든 파일에 대해 작업한다).</li> + <li><strong>.gitignore</strong> 파일을 열어서, 아래 코드를 맨 밑에 복사하고, 저장하라 ( 이 파일은 기본 설정에 의해 git에 저장되지 말아야할 파일을 구분하는데 사용된다). + <pre># Text backup files +*.bak + +#Database +*.sqlite3</pre> + </li> + <li>커맨드 프로프트/터미널을 열고 <code>add</code>명령으로 모든 파일을 git에 등록한다. + <pre class="brush: bash">git add -A +</pre> + </li> + <li>status 명령을 사용하여 등록하고자 하는 파일이 맞는지 확인한다 ( 당신은 소스파일만 등록 하길 원하고 바이너리나 임시 파일은 원치 않을 것이다). 명령을 실행하면 아래와 유사하게 나온다. + <pre>> git status +On branch master +Your branch is up-to-date with 'origin/master'. +Changes to be committed: + (use "git reset HEAD <file>..." to unstage) + + modified: .gitignore + new file: catalog/__init__.py + ... + new file: catalog/migrations/0001_initial.py + ... + new file: templates/registration/password_reset_form.html</pre> + </li> + <li>위의 결과에 만족했다면, commit 명령으로 파일의 로컬 저장소 등록을 확정한다: + <pre class="brush: bash">git commit -m "First version of application moved into github"</pre> + </li> + <li>다음 명령을 이용하여 Github 웹사이트와 로컬 저장소를 동기화 한다: + <pre>git push origin master</pre> + </li> +</ol> + +<p>이런 작업이 완료된 후, repo를 생성한 Github 페이지로 다시 가서, 페이지를 새로 로딩하여, 전체 어플리케이션이 모두 업로드된것인지 확인할 수 있어야 한다. 이후로 파일 변경 사항이 발생하면 add/commit/push 순서로 명령을 사용하여 저장소를 업데이트 할 수 있다.</p> + +<div class="note"> +<p><strong>한가지 팁:</strong> 이쯤에서 당신의 "변형 없이 순수한(<a href="https://en.wikipedia.org/wiki/Vanilla_software">vanilla</a>)" 프로젝트를 백업하는것이 좋다. - 이어지는 섹션에서 해볼 작업들은 어떤 플랫폼(혹은 개발작업) 에서는 유용하지만 다른 곳에서는 그렇지 않을 수 있기 때문이다.</p> + +<p>백업을 하는 가장 좋은 방법은 git을 사용하여 관리하는 것이다. git을 사용하면, 특정 구 버전으로 갈수 있을 뿐만 아니라, 이것을 운영관련 변경사항으로 부터 분리된 "브랜치(branch)"로 유지보수할 수있고, 운영 브랜치와 개발 브랜치간에 좋은 부분만 선별하여 적용할 수 있다. <a href="https://help.github.com/articles/good-resources-for-learning-git-and-github/">Git 공부하기</a> 는 수고를 들여 배울가치가 있지만 이 글의 주제를 벗어난다.</p> + +<p>백업을 하는 가장 쉬운방법은 단순히 파일을 다른 위치에 복제하는 것이다. 당신의 git 관련 지식에 맞춰, 어떤 방법이든 사용하도록 하자 !</p> +</div> + +<h3 id="Heroku에_맞춰_앱을_수정하기">Heroku에 맞춰 앱을 수정하기</h3> + +<p>이번 섹션에서는 LocalLibray 어플리케이션이 Heroku상에서 작동할 수 있도록 수정할 필요가 있는 변경사항에 대해 설명한다. Heroku 문서인 <a href="https://devcenter.heroku.com/articles/getting-started-with-python#introduction">Django로 Heroku 시작해보기</a> 에서 나온 지시사항들은 당신이 로컬 개발 환경의 실행 또한 Heroku 클라이언트를 사용할 것으로 가정하고 있지만, 우리가 여기서 제시할 변경사항은 기존의 Django 개발 서버및 이제껏 배워온 작업방식과 호환될 것이다.</p> + +<h4 id="Procfile_작성하기">Procfile 작성하기</h4> + +<p>어플리케이션의 프로세스 타입과 엔트리 포인트를 선언하기 위해 GiHub 저장소의 root 폴더에 <code>Procfile</code> 파일을 (확장자 없이 ) 생성한다. 아래 문장을 해당 파일에 작성한다:</p> + +<pre>web: gunicorn locallibrary.wsgi --log-file -</pre> + +<p>"<code>web:</code>" 구문은 Heroku에게 이것이 웹 다이노이며 HTTP 트래픽을 받을수 있다는 것을 알려준다. 이 다이노에서 시작할 프로세스는 <em>gunicorn 인데 Heroku가 추천하는 인기있는 웹 어플리케이션 서버이다. </em><code>locallibrary.wsgi</code><em> ( 어플리케이션 뼈대로 생성된: </em><strong>/locallibrary/wsgi.py</strong>) <em>모듈의 설정 정보를 이용하여 </em>Gunicorn을 구동시킨다.</p> + +<h4 id="Gunicorn_설치하기">Gunicorn 설치하기</h4> + +<p><a href="http://gunicorn.org/">Gunicorn</a> 은 Django와 함께 사용되는 용도로 Heroku에서 추천되는 HTTP server 이다 (바로 위의 Procfile 에서 미리 본 바와 같다). 하나의 다이노에서 여러개의 Python 동시 프로세스를 실행할 수 있는 WSGI 어플리케이션을 위한 순수 Python으로 작성된 HTTP server 다. ( 추가 정보를 얻으려면 <a href="https://devcenter.heroku.com/articles/python-gunicorn">Gunicorn으로 Python 어플리케이션 배포하기</a> ( Heroku 문서) 참고하라).</p> + +<p>개발기간중에는 LocalLibrary 어플리케이션을 서비스하기 위해 Gunicorn을 필요로 하진 않겠지만, Heroku에서 원격 서버를 셋업하기 위한 <a href="https://developer.mozilla.org/ko/docs/Learn/Server-side/Django/Deployment$edit#requirements">요구조건</a> 의 일부이므로 Gunicorn을 설치할 것이다. </p> + +<p>아래와 같이 커맨드라인에서 pip를 이용하여 <em>Gunicorn</em> 설치한다 (pip는 <a href="/en-US/docs/Learn/Server-side/Django/development_environment">개발 환경 구축하기</a> 단계에서 설치했다):</p> + +<pre class="brush: bash">pip3 install gunicorn +</pre> + +<h4 id="Database_설정하기">Database 설정하기</h4> + +<p>디폴트로 설정되었던 SQLite 데이타베이스는 Heroku에서는 사용할 수 없다. 이유는 SQLite가 파일 베이스로 동작하는 시스템인데, Heroku는 단기-수명(ephemeral) 파일 시스템을 사용하므로 어플리케이션이 재시작되면 파일이 삭제되기 때문이다 ( 보통 하루에 한 번, 어플리케이션이나 그에 딸린 설정 변수가 변경되면 재시작 된다) . </p> + +<p>이런 상황에 대처하는 Heroku의 메커니즘은 <a href="https://elements.heroku.com/addons#data-stores">database 애드온</a>을 사용하고 애드온에 의해 설정되는 환경 <a href="https://devcenter.heroku.com/articles/config-vars">설정 변수</a>로 부터의 정보를 이용하여 웹 어플리케이션을 설정하는 것이다. 많은 데이타베이스 옵션이 있지만, Heroku postgres 데이터베이스의 <a href="https://devcenter.heroku.com/articles/heroku-postgres-plans#plan-tiers">Hobby tier</a>를 사용할것인데, 이것은 무료이고, Django가 지원하며, 무료 hobby dyno plan tier를 사용할 때 신규 Heroku 앱에 자동으로 추가된다.</p> + +<p>데이터베이스 연결 정보는 <code>DATABASE_URL</code> 라는 설졍변수를 사용해 웹 다이노에 제공된다. Heroku는 , 이 정보를 Django에 하드 코딩 해넣기 보다는, 개발자들이 <a href="https://warehouse.python.org/project/dj-database-url/">dj-database-url</a> 패키지를 사용하여 <code>DATABASE_URL</code> 환경 변수를 분석하여 자동적으로 Django가 원하는 설정 형식으로 변환하는 것을 추천한다. <em>dj-database-url</em> 패키지를 설치하는것에 외에도, Django에서 Postgres 데이터베이스로 작업하기 위해서는 <a href="http://initd.org/psycopg/">psycopg2</a> 도 설치해야 한다.</p> + +<h5 id="dj-database-url_(환경_변수를_통한_Django_데이터베이스_설정_)_설치하기">dj-database-url (환경 변수를 통한 Django 데이터베이스 설정 ) 설치하기</h5> + +<p>Heroku에서 원격 서버에 설치하기 위한 <a href="https://developer.mozilla.org/ko/docs/Learn/Server-side/Django/Deploymentt#requirements">요구조건</a>의 일부가 되었으니, <em>dj-database-url</em> 를 로컬에 설치한다:</p> + +<pre>$ pip3 install dj-database-url +</pre> + +<h5 id="settings.py_수정하기">settings.py 수정하기</h5> + +<p><strong>/locallibrary/settings.py</strong> 를 열고 아래 설정코드를 파일의 맨 밑에 복사해 넣는다:</p> + +<pre># Heroku: Update database configuration from $DATABASE_URL. +import dj_database_url +db_from_env = dj_database_url.config(conn_max_age=500) +DATABASES['default'].update(db_from_env)</pre> + +<div class="note"> +<p><strong>주목할 점:</strong></p> + +<ul> + <li><code>DATABASE_URL</code> 환경변수가 개발용 컴퓨터에는 없을것이므로 개발단계에서는 계속 SQLite를 사용한다.</li> + <li> <code>conn_max_age=500</code> 설정을 하면 연결상태가 지속될 수 있는데, 매번 요청 주기에 연결을 새로 하는것보다 이렇게 하는 것이 훨신 효율적이다. 하지만 이것은 옵션이며 불 필요하면 제거해도 된다.</li> +</ul> +</div> + +<h5 id="psycopg2_(Python_Postgres_데이터베이스_지원용)_설치하기">psycopg2 (Python Postgres 데이터베이스 지원용) 설치하기</h5> + +<p>Django에서 Postgres 데이터베이스로 작업하기 위해서는 <em>psycopg2</em> 가 필요하므로 Heroku에 원격 서버를 생성하기 위해서는( 아래 요구조건 섹션에 논의된 바와 같이) <a href="#requirements">requirements.txt</a> 파일에 이 항목을 추가할 필요가 있다.</p> + +<p>환경 변수가 로컬 환경에서 존재하지 않기 때문에, 로컬에서 Django는 디폴트로 SQLite를 사용할 것이다. 당신이 Postgres로 완전히 전환해서 개발과 운영 모두 Heroku 무료 단계 데이터베이스를 사용하길 원한다면 그렇게 할 수 있다. 예를 들면, Linux 기반 시스템에 psycopg2와 관련 모듈을 설치하려면, 아래 bash/터미널 명령을 사용하면 된다:</p> + +<pre class="brush: bash"><code>sudo apt-get install python-pip python-dev libpq-dev postgresql postgresql-contrib</code> +pip3 install psycopg2 +</pre> + +<p>다른 플랫폼에 대한 설치방법은 <a href="http://initd.org/psycopg/docs/install.html">이곳 psycopg2 웹사이트</a> 에서 찾아볼 수 있다.</p> + +<p>하지만, 당신이 Heroku에 사이트를 적용하기 위한 ( <code>requirements.txt</code> (아래에 나옴)에서) 요구조건 으로서만 맞추려고 한다면, 굳이 이렇게 PostGreSQL을 로컬 컴퓨터에 설치할 필요까지는 없다.</p> + +<h4 id="운영환경에서_정적_파일(static_file)_지원하기">운영환경에서 정적 파일(static file) 지원하기</h4> + +<p>개발 단계동안 Django와 Django 개발용 웹 서버를 사용하여 정적 파일을 지원해 왔다 (CSS, JavaScript, 등등.). 운영 환경에서는 보통 콘텐츠 전달 네트웍 ( CDN) 이나 웹서버에서 정적 파일을 지원한다.</p> + +<div class="note"> +<p><strong>주목할 점:</strong> Django/웹 어플리케이션으로 직접 정적 파일을 지원하는 것은 비효율적이다. 웹서버에 의해 직접 조작되거나 CDN으로 완전히 분리하는 것에 비해, 불필요한 추가적인 코드가 요청(requests)에 추가되기 때문이다. 이런 사항은 로컬에서 진행되는 개발단계에서는 영향이 크진 않지만, 운영 단계에서 같은 방식으로 사용하려 한다면 심각한 성능저하 상황이 발생할 수 있다. </p> +</div> + +<p>Django 웹 어플리케이션으로부터 분리하여 정적파일을 쉽게 호스팅하기 위해, Django는 개발용 정적 파일을 수집하는 collectstatic 도구를 제공한다 (collectstatic이 실행될 때 어느곳에서 파일이 수집되어야 하는지 정의한 설정 변수들이 있다). Django 템플릿은 정적 파일 종류의 호스팅 위치를 <code>STATIC_URL</code> 설정 변수로 알려주며, 정적 파일의 위치가 다른 호스트/서버로 이동되면 여기서 바꿀 수 있도록 한다.</p> + +<p>관련 설정 변수는 다음과 같다:</p> + +<ul> + <li><code>STATIC_URL</code>: 이것은 베이스 URL 위치인데 이곳에서 정적 파일들이 지원된다. 예를 들면 CDN과 같은곳이다. 베이스 템플릿에서 접근하는 정적 템플릿 변수에 사용된다. ( <a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django 튜토리얼 파트 5: 홈페이지 작성하기</a> 를 참고하라).</li> + <li><code>STATIC_ROOT</code>: 이것은 Django의 "collectstatic" 도구로 템플릿에서 참조하는 모든 정적 파일을 모집하는 디렉토리로 가는 절대 경로이다. 일단 수집되면, 이것들은 파일이 어떤곳에서 호스팅되든지 단체로 업로드 될 수 있다.</li> + <li><code>STATICFILES_DIRS</code>: 이것은 Django의 colletstatic 도구가 정적 파일을 탐색할 추가적인 디렉토리를 나열한다.</li> +</ul> + +<h5 id="settings.py_수정하기_2">settings.py 수정하기</h5> + +<p><strong>/locallibrary/settings.py</strong> 파일을 열고 아래 설정을 파일의 맨 밑으로 복사한다. <code>BASE_DIR</code> 는 파일에 이미 정의되어 있었어야 한다. ( <code>STATIC_URL</code> 도 설정파일이 생성될 때 정의되었을 것이다. 중복되는 이전의 설정은, 지우지 않아도 문제는 없겠지만, 제거하는 것이 좋다).</p> + +<pre># Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/2.0/howto/static-files/ + +# The absolute path to the directory where collectstatic will collect static files for deployment. +STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') + +# The URL to use when referring to static files (where they will be served from) +STATIC_URL = '/static/' +</pre> + +<p>실제로는, 다음 섹션에서 설치하고 설정할, <a href="https://warehouse.python.org/project/whitenoise/">WhiteNoise</a> 라는 이름의 라이브러리를 이용하여 파일을 관리할 것이다.</p> + +<p>더 많은 정보가 필요하면 <a href="https://devcenter.heroku.com/articles/django-assets">Django and Static Assets</a> (Heroku docs) 를 참고한다.</p> + +<h4 id="Whitenoise_적용하기">Whitenoise 적용하기</h4> + +<p>운영환경에서 정적 파일을 관리하기 위한 수많은 방법이 있다 (바로 앞 섹션에서 관련된 Django 설정을 봤다). Heroku는 <a href="https://warehouse.python.org/project/whitenoise/">WhiteNoise</a> 프로젝트를 이용하여 운영환경의 Gunicorn상에서 직접 정적 자원을 관리하는 것을 추천한다.</p> + +<div class="note"> +<p><strong>주목할 점: </strong>Heroku는 자동적으로 collectstatic을 호출하고 사용자 어플리케이션을 업로드한 후 WhiteNoise로 정적파일을 사용할 수 있도록 준비한다. WhiteNoise의 동작 방식과 이 도구를 적용하는 것이 좀더 효율적인 이유에 대한 설명은 <a href="https://warehouse.python.org/project/whitenoise/">WhiteNoise</a> 문서를 참조한다.</p> +</div> + +<p>본 프로젝트에 <em>WhiteNoise를 적용하는 단계적 방법은 다음과 같다 </em>:</p> + +<h5 id="WhiteNoise_설치하기">WhiteNoise 설치하기</h5> + +<p>아래 명령으로 whitenoise를 로컬에 설치한다 :</p> + +<pre>$ pip3 install whitenoise +</pre> + +<h5 id="settings.py_수정하기_3">settings.py 수정하기</h5> + +<p>사용자 Django 어플리케이션에 WhiteNoise를 설치하기 위해, <strong>/locallibrary/settings.py</strong> 를 열고, <code>MIDDLEWARE</code> 설정을 찾아서 <code>SecurityMiddleware</code> 바로 밑의 목록의 윗부분에 <code>WhiteNoiseMiddleware</code> 를 추가 한다 :</p> + +<pre>MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + <strong>'whitenoise.middleware.WhiteNoiseMiddleware',</strong> + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] +</pre> + +<p>선택 사항으로, 파일이 서빙될 때 정적 파일의 크기를 줄일 수 있다. (이 방식이 좀더 효율적이다). Just add the following to the bottom of <strong>/locallibrary/settings.py</strong>:</p> + +<pre># Simplified static file serving. +# https://warehouse.python.org/project/whitenoise/ +STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage' +</pre> + +<h4 id="파이썬_관련_라이브러리_(Requirements)_설치하기">파이썬 관련 라이브러리 (Requirements) 설치하기</h4> + +<p>웹 어플리케이션의 Python 관련 라이브러리들은 저장소의 루트에 위치한 <strong>requirements.txt</strong> 라는 파일에 저장되어야 한다. 그러면 Heroku는 환경을 재구성할 때 이 패키지들을 자동적으로 설치할 것이다. 커맨드 라인에서 pip 명령을 이용해 이 파일을 생성할 수 있다. ( 아래 명령을 repo 루트 디렉토리에서 실행한다):</p> + +<pre class="brush: bash">pip3 freeze > requirements.txt</pre> + +<p>여러가지 관련 라이브러리를 위에서 설치했다면, <strong>requirements.txt</strong> 파일은 최소한 아래 나열된 항목들을 가지고 있어야 한다. ( 버전 숫자는 다를수도 있다). 명확히 이 어플리케이션을 위해 설치한것이 아니라면 , 아래 목록을 제외한 라이브러리는 지우는 것이 좋다.</p> + +<pre>dj-database-url==0.4.1 +Django==2.0 +gunicorn==19.6.0 +<strong>psycopg2==2.6.2</strong> +whitenoise==3.2.2 +</pre> + +<div class="note"> +<p>위 목록에 <strong>psycopg2</strong> 줄이 있다는 것을 주의해야 한다! 로컬환경에서 이 라이브러리를 설치한 적이 없더라도 이 줄은 <strong>requirements.txt</strong> 파일에 추가해야 한다.</p> +</div> + +<h4 id="Runtime_파일_추가하기">Runtime 파일 추가하기</h4> + +<p><strong>runtime.txt</strong> 파일이 존재한다면 Heroku에게 웹사이트에서 사용할 프로그래밍 언어를 알려준다. 아래 문구를 추가하여 저장소의 루트에 runtime.txt 파일을 생성한다:</p> + +<pre>python-3.6.4</pre> + +<div class="note"> +<p><strong>주목할 점:</strong> Heroku가 지원하는 <a href="https://devcenter.heroku.com/articles/python-support#supported-python-runtimes">Python 실행버전</a> ( 이 글을 쓰는 당시에는 위 버전을 포함한다)은 그리 많지 않다. Heroku는 이 파일에 지정된 버전에 개의치 않고 지원되는 실행버전을 사용할 것이다.</p> +</div> + +<h4 id="Github에_변경사항을_저장하고_테스트_다시하기">Github에 변경사항을 저장하고 테스트 다시하기</h4> + +<p>다음으로 모든 변경사항을 Github에 저장하자. 아래 명령을 ( 저장소 범위내 위치에서) 터미널에 입력한다 :</p> + +<pre class="brush: bash">git add -A +git commit -m "Added files and changes required for deployment to heroku" +git push origin master</pre> + +<p>계속 진행하기전에, 로컬에서 사이트를 다시 테스트 해서 위의 변경사항에 의해 영향받은부분이 없는지 확인한다. 지금까지 해온 것 처럼 개발용 웹 서버를 실행하고 브라우저 상에서 여전히 기대한 대로 동작하는지 체크한다.</p> + +<pre class="brush: bash">python3 manage.py runserver</pre> + +<p>이제 Heroku에 LocalLibrary의 배포를 시작할 준비가 다 되었다.</p> + +<h3 id="Heroku_계정_생성하기">Heroku 계정 생성하기</h3> + +<p>Heroku 이용을 시작 하려면 계정을 한 개 생성해야 한다 :</p> + +<ul> + <li><a href="https://www.heroku.com/">www.heroku.com</a> 사이트로 가서 <strong>SIGN UP FOR FREE</strong> 버튼을 클릭한다.</li> + <li>세부 정보를 입력하고 <strong>CREATE FREE ACCOUNT</strong> 버튼을 누른다. 당신은 가입 이메일에서 계정을 확인 하도록 요청받을 것이다.</li> + <li>가입 이메일에서 계정 활성화 요청 링크 (account activation link) 를 클릭하면 웹 브라우저 상에서 당신의 계정 위치로 이동될 것이다.</li> + <li>당신의 암호를 입력하고 <strong>SET PASSWORD AND LOGIN</strong> 버튼을 클릭하라</li> + <li>로그인이 되면 Heroku 대시보드로 이동될 것이다: <a href="https://dashboard.heroku.com/apps">https://dashboard.heroku.com/apps</a>.</li> +</ul> + +<h3 id="client_설치하기">client 설치하기</h3> + +<p>여기의 <a href="https://devcenter.heroku.com/articles/getting-started-with-python#set-up">Heroku 지시사항</a> 에 따라 Heroku 클라이언트를 다운로드하고 설치하라.</p> + +<p>클라이언트를 설치한후에 명령어를 실행할 수 있다. 예를 들면, 클라이언트에 대한 도움말을 얻고 싶다면 아래 명령을 실행한다:</p> + +<pre class="brush: bash">heroku help +</pre> + +<h3 id="웹사이트를_생성하고_업로드하기">웹사이트를 생성하고 업로드하기</h3> + +<p>앱을 생성하기 위해 "create" 명령을 저장소의 루트 디렉토리에서 실행한다. 이명령은 로컬 컴퓨터의 git 환경에 heroku라는 이름의 git의 원격 저장소(remote) ("원격 저장소의 지정자(pointer)")를 생성한다.</p> + +<pre class="brush: bash">heroku create</pre> + +<div class="note"> +<p><strong>주목할 점:</strong> 원한다면 원격 저장소(remote)에 이름을 붙일 수 있는데 . "create" 다음에 값을 추가하면 된다. 아무것도 붙이지 않으면 랜덤으로 생성된 이름을 가진다. 이 이름은 기본 URL로 사용된다.</p> +</div> + +<p>그다음에 아래와 같은 명령으로 앱을 Heroku 저장소에 등록(push)할 수 있다. 이 명령은 앱을 업로드하고, 다이노안에 앱을 포장(pakage)하며, colletstatic을 실행하고 사이트가 시작 되도록 한다.</p> + +<pre class="brush: bash">git push heroku master</pre> + +<p>운이 좋다면, 앱은 이제 사이트상에서 "실행(running)" 상태에 있게되겠지만, 어플리케이션을 위한 데이터베이스 테이블을 구성하지 않았기 때문에 제대로 동작하지 않을 것이다. 이 작업을 위해 <code>heroku run</code> 명령을 사용해 migrate 작업을 수행할 "<a href="https://devcenter.heroku.com/articles/deploying-python#one-off-dynos">one off 다이노</a>" 를 시작시켜야 한다. 아래 명령을 터미널에 입력하라 :</p> + +<pre class="brush: bash">heroku run python manage.py migrate</pre> + +<p>책과 저자도 추가할 수 있어야 하니까 다시 one-off 다이노를 이용하여 관리자 아이디 또한 생성하자:</p> + +<pre class="brush: bash">heroku run python manage.py createsuperuser</pre> + +<p>일단 이 작업이 완료되면, 사이트를 볼 수 있다. 아직 아무 책도 없긴 하지만 사이트가 동작한다. 신규 웹사이트를 브라우저로 보고 싶으면 아래 명령을 사용하라 :</p> + +<pre class="brush: bash">heroku open</pre> + +<p>admin 사이트에서 책 몇개를 생성하고 사이트가 기대한대로 동작하는지 확인하라.</p> + +<h3 id="애드온_관리하기">애드온 관리하기</h3> + +<p><code>heroku addons</code> 명령으로 앱의 애드온 적용에 대해 확인할 수 있다. 이 명령은 모든 애드온을 나열하고, 가격과 상태를 보여준다.</p> + +<pre class="brush: bash">>heroku addons + +Add-on Plan Price State +───────────────────────────────────────── ───────── ───── ─────── +heroku-postgresql (postgresql-flat-26536) hobby-dev free created + └─ as DATABASE</pre> + +<p>여기서 단 한개의 애드온만 있는데, 바로 postgres SQL 데이터베이스 이다. 이것은 무료이고, 앱을 생성할 때 자동적으로 생성되었다. 데이터베이스 애드온을 ( 다른 어떤 애드온이라도) 좀 더 자세히 조사하기 위해 아래 명령으로 웹 페이지 열 수 있다 (open) :</p> + +<pre class="brush: bash">heroku addons:open heroku-postgresql +</pre> + +<p>애드온을 생성하고(create), 제거하고(destroy), 업그레이드하고(upgrade), 다운그레이드하는(downgrade) 다른 명령들도 있다. ( 여는 명령(open)과 유사한 문법을 사용한다). 좀 더 자세한 정보는 <a href="https://devcenter.heroku.com/articles/managing-add-ons">Managing Add-ons</a> (Heroku 문서) 를 참조하라.</p> + +<h3 id="구성_변수_(_configuration_variables)_설정하기">구성 변수 ( configuration variables) 설정하기</h3> + +<p><code>heroku config</code> 명령을 이용하여 사이트의 구성 변수를 확인할 수 있다. 아래에서 현재 한개의 변수만 가지는 것을 확인할 수있는데, <code>DATABASE_URL</code> 변수는 데이터베이스를 설정하는 데 사용된다.</p> + +<pre class="brush: bash">>heroku config + +=== locallibrary Config Vars +DATABASE_URL: postgres://uzfnbcyxidzgrl:j2jkUFDF6OGGqxkgg7Hk3ilbZI@ec2-54-243-201-144.compute-1.amazonaws.com:5432/dbftm4qgh3kda3</pre> + +<p>위에서 공부한 <a href="#Getting_your_website_ready_to_publish">웹 사이트 공개(publish) 준비하기</a> 섹션을 다시 떠올려보면, <code>DJANGO_SECRET_KEY</code>와 <code>DJANGO_DEBUG</code> 환경 변수를 설정해야 한다. 지금 이 작업을 하자.</p> + +<div class="note"> +<p><strong>주목할 점:</strong> secret key는 정말로 비밀이 유지되어야 한다! 새로운 키를 만들어 내는 한가지 방법은 새로운 Django 프로젝트를 생성하고 (<code>django-admin startproject someprojectname</code>) 신규 프로젝트의 <strong>settings.py</strong>에서 생성된 키를 가져오는 것이다.</p> +</div> + +<p><code>DJANGO_SECRET_KEY</code> 를 <code>config:set</code> 명령을 통해 설정한다(아래 예제와 같이). 당신 자신의 secret key를 사용해야 한다는 것을 기억하자!</p> + +<pre class="brush: bash">>heroku config:set DJANGO_SECRET_KEY=eu09(ilk6@4sfdofb=b_2ht@vad*$ehh9-)3u_83+y%(+phh&= + +Setting DJANGO_SECRET_KEY and restarting locallibrary... done, v7 +DJANGO_SECRET_KEY: eu09(ilk6@4sfdofb=b_2ht@vad*$ehh9-)3u_83+y%(+phh +</pre> + +<p><code>DJANGO_DEBUG</code> 도 유사하게 설정한다 :</p> + +<pre class="brush: bash">>heroku config:set <code>DJANGO_DEBUG= + +Setting DJANGO_DEBUG and restarting locallibrary... done, v8</code></pre> + +<p>지금 웹사이트를 방문한다면 "Bad request" 에러를 만나게 되는데 이것은 (보안 조치상) <code>DEBUG=False</code> 로 설정되어 있여서 <a href="https://docs.djangoproject.com/en/2.0/ref/settings/#allowed-hosts">ALLOWED_HOSTS</a> 설정이 요구되기 때문이다. <strong>/locallibrary/settings.py</strong> 파일을 열고 아래와 같이 <code>ALLOWED_HOSTS</code> 설정을 수정하여 베이스 앱 url과 (예를들면, 'locallibrary1234.herokuapp.com') 로컬 개발 환경 웹서버에서 지금까지 사용해온 URL을 추가하라.</p> + +<pre class="brush: python">ALLOWED_HOSTS = ['<your app URL without the https:// prefix>.herokuapp.com','127.0.0.1'] +# For example: +# ALLOWED_HOSTS = ['fathomless-scrubland-30645.herokuapp.com','127.0.0.1'] +</pre> + +<p>그다음 지금 설정한 것들을 저장하고 Github 저장소와 Herok에 반영한다 :</p> + +<pre class="brush: bash">git add -A +git commit -m 'Update ALLOWED_HOSTS with site and development server URL' +git push origin master +git push heroku master</pre> + +<div class="note"> +<p>Heroku에 사이트 업데이트하는 것을 완료한후, 존재하지 않는 주소URL(예를 들면, <strong>/catalog/doesnotexist/</strong>) 을 입력해 보자. 이전에는 이런 경우 자세한 설명이 담긴 디버그 페이지를 보여주었었지만, 이제는 단순한 "Not Found" 페이지가 보일것이다.</p> +</div> + +<h3 id="디버깅_하기">디버깅 하기</h3> + +<p>Heroku 클라이언트는 디버깅을 위한 몇가지 도구를 제공한다 :</p> + +<pre class="brush: bash">heroku logs # Show current logs +heroku logs --tail # Show current logs and keep updating with any new results +heroku config:set DEBUG_COLLECTSTATIC=1 # Add additional logging for collectstatic (this tool is run automatically during a build) +heroku ps #Display dyno status +</pre> + +<p>이것들보다 더 자세한 정보가 필요하다면 <a href="https://docs.djangoproject.com/en/2.0/topics/logging/">Django Logging</a> 을 자세히 살펴보는 것이 좋을것이다.</p> + +<ul> +</ul> + +<h2 id="요약">요약</h2> + +<p>이렇게 Django 앱을 운영환경에서 구성해보는 튜토리얼이 끝났고. 지금까지 공부해온 Django 튜토리얼 시리즈도 이것으로 마무리가 되었다. 이 시리즈가 당신에 유용한 자료이길 바란다. 앞에서 설명한 모든 단계를 커버하는 버전의, <a href="https://github.com/mdn/django-locallibrary-tutorial">Github상의 소스 코드는 이곳에서</a> 확인할 수 있다.<br> + <br> + 다음 단계는 마지막으로 몇개의 기사를 읽어보고, 평가작업을 완성하는 것이다.</p> + +<h2 id="See_also">See also</h2> + +<ul> + <li><a href="https://docs.djangoproject.com/en/2.0/howto/deployment/">Deploying Django</a> (Django docs) + + <ul> + <li><a href="https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/">Deployment checklist</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.0/howto/static-files/deployment/">Deploying static files</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.0/howto/deployment/wsgi/">How to deploy with WSGI</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.0/howto/deployment/wsgi/modwsgi/">How to use Django with Apache and mod_wsgi</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.0/howto/deployment/wsgi/gunicorn/">How to use Django with Gunicorn</a> (Django docs)</li> + </ul> + </li> + <li>Heroku + <ul> + <li><a href="https://devcenter.heroku.com/articles/django-app-configuration">Configuring Django apps for Heroku</a> (Heroku docs)</li> + <li><a href="https://devcenter.heroku.com/articles/getting-started-with-python#introduction">Getting Started on Heroku with Django</a> (Heroku docs)</li> + <li><a href="https://devcenter.heroku.com/articles/django-assets">Django and Static Assets</a> (Heroku docs)</li> + <li><a href="https://devcenter.heroku.com/articles/python-concurrency-and-database-connections">Concurrency and Database Connections in Django</a> (Heroku docs)</li> + <li><a href="https://devcenter.heroku.com/articles/how-heroku-works">How Heroku works</a> (Heroku docs)</li> + <li><a href="https://devcenter.heroku.com/articles/dynos">Dynos and the Dyno Manager</a> (Heroku docs)</li> + <li><a href="https://devcenter.heroku.com/articles/config-vars">Configuration and Config Vars</a> (Heroku docs)</li> + <li><a href="https://devcenter.heroku.com/articles/limits">Limits</a> (Heroku docs)</li> + <li><a href="https://devcenter.heroku.com/articles/python-gunicorn">Deploying Python applications with Gunicorn</a> (Heroku docs)</li> + <li><a href="https://devcenter.heroku.com/articles/deploying-python">Deploying Python and Django apps on Heroku</a> (Heroku docs)</li> + <li><a href="https://devcenter.heroku.com/search?q=django">Other Heroku Django docs</a></li> + </ul> + </li> + <li>Digital Ocean + <ul> + <li><a href="https://www.digitalocean.com/community/tutorials/how-to-serve-django-applications-with-uwsgi-and-nginx-on-ubuntu-16-04">How To Serve Django Applications with uWSGI and Nginx on Ubuntu 16.04</a></li> + <li><a href="https://www.digitalocean.com/community/tutorials?q=django">Other Digital Ocean Django community docs</a></li> + </ul> + </li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Django/Testing", "Learn/Server-side/Django/web_application_security", "Learn/Server-side/Django")}}</p> + +<p> </p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Server-side/Django/Introduction">Django introduction</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/development_environment">Setting up a Django development environment</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Django Tutorial: The Local Library website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django Tutorial Part 2: Creating a skeleton website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Models">Django Tutorial Part 3: Using models</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Admin_site">Django Tutorial Part 4: Django admin site</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django Tutorial Part 5: Creating our home page</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Generic_views">Django Tutorial Part 6: Generic list and detail views</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Sessions">Django Tutorial Part 7: Sessions framework</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Authentication">Django Tutorial Part 8: User authentication and permissions</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Forms">Django Tutorial Part 9: Working with forms</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Testing">Django Tutorial Part 10: Testing a Django web application</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Django Tutorial Part 11: Deploying Django to production</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/web_application_security">Django web application security</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></li> +</ul> + +<p> </p> diff --git a/files/ko/learn/server-side/django/development_environment/index.html b/files/ko/learn/server-side/django/development_environment/index.html new file mode 100644 index 0000000000..0e31882131 --- /dev/null +++ b/files/ko/learn/server-side/django/development_environment/index.html @@ -0,0 +1,439 @@ +--- +title: Django 개발 환경 세팅하기 +slug: Learn/Server-side/Django/development_environment +tags: + - 개발환경 + - 들어가기 + - 설치 + - 장고 + - 초심자 + - 파이썬 +translation_of: Learn/Server-side/Django/development_environment +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Django/Introduction", "Learn/Server-side/Django/Tutorial_local_library_website", "Learn/Server-side/Django")}}</div> + +<p class="summary">이제 장고가 무엇인지 알았으니, 윈도우, 리눅스(우분투), 맥 OS X에서 어떻게 장고 개발환경을 세팅하는지, 설치 후에는 어떻게 테스트하는지 살펴보겠습니다. 즉 이 문서를 통해서는 사용하고 있는 운영체제가 무엇인지와 상관없이 장고 어플리케이션 개발을 시작하기 위해 필요한 것들을 배우게 됩니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">미리 필요한 것:</th> + <td> + <p>터미널 또는 커맨드 창을 열 수 있어야 합니다. 또, 자신이 사용하는 PC의 운영체제에 따라 PC에 소프트웨어 패키지를 설치할 수 있어야 합니다.</p> + </td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>장고가 컴퓨터에서 실행될 수 있도록 개발 환경을 세팅합니다.</td> + </tr> + </tbody> +</table> + +<h2 id="장고_개발_환경_개요">장고 개발 환경 개요</h2> + +<p>장고는 개발 환경을 세팅하고 웹 어플리케이션을 개발하는 것이 매우 쉽습니다. 이 섹션에서는 개발 환경이 제공하는 것들과, 개발 환경 세팅 시 옵션 사항을 알아봅니다. 또 우분투, 맥 OS X, 윈도우에서 장고 개발 환경을 설치하는 방법과 설치 후 테스트하는 방법을 설명합니다.</p> + +<h3 id="장고_개발_환경이란">장고 개발 환경이란?</h3> + +<p>장고 개발 환경이란, 장고를 로컬 컴퓨터에 설치하여 장고 어플리케이션을 개발, 실행, 테스트할 수 있는 환경을 말합니다. 로컬 컴퓨터는 자신이 어플리케이션을 개발하는데 사용하는 컴퓨터입니다. 어플리케이션을 실제 배포하기 전에 로컬 컴퓨터 위에서 어플리케이션을 실행 및 테스트할 수 있습니다.</p> + +<p>장고 자체가 제공하는 주요 툴에는 장고 프로젝트를 생성하고 작업하기 위한 파이썬 스크립트들과 심플한 개발용 웹 서버가 있습니다. 이 개발용 웹 서버로 우리는 로컬 컴퓨터에서 개발한 장고 어플리케이션을 같은 로컬 컴퓨터에서 테스트해 볼 수 있습니다. 예를 들면, 자신의 PC에서 개발한 장고 웹 어플리케이션을 크롬 브라우저와 같은 웹 브라우저 상에서 실행하고 테스트해볼 수 있습니다.</p> + +<p>앞서 설명한 것 외에도 장고 개발 환경은 여러 툴을 제공합니다. 코드 작성을 돕는 텍스트 에디터와 IDE, 소스코드의 버전을 안전하게 관리하기 위한 Git과 같은 소스 관리 도구와 같은 것들이 있습니다. 그러나 이것들은 여기서는 다루지 않습니다. 또 여기서는 미리 텍스트 에디터를 설치했다고 가정할 것입니다. 그러므로 텍스트 에디터를 아직 설치하지 않았다면 설치해주세요. 자주 사용하는 텍스트 에디터로는 <a href="https://www.sublimetext.com/3">Sublime Text 3</a>, <a href="https://wiki.gnome.org/Apps/Gedit#Download">Gedit</a>, <a href="https://atom.io/">Atom</a> 등이 있습니다.</p> + +<h3 id="장고_설치_옵션">장고 설치 옵션</h3> + +<p>장고는 설치 및 구성에서 매우 유연합니다.</p> + +<p>장고는 다음 사항이 가능합니다:</p> + +<ul> + <li>여러 운영 체제에서 설치가 가능합니다.</li> + <li>소스에서, 파이썬 패키지 인덱스(PyPi)에서, 그리고 많은 경우 호스트 컴퓨터의 패키지 매니저 어플리케이션에서 설치가 가능합니다.</li> + <li>별도로 설치 및 구성되어있어야 하는 여러가지 데이터베이스 중 하나를 사용하도록 설정할 수 있습니다.</li> + <li>메인 시스템의 파이썬 환경 또는 별도의 파이썬 가상 환경에서 실행됩니다.</li> +</ul> + +<p>이러한 각각의 옵션들은 모두 조금씩 다른 구성과 설치가 필요합니다. 이어지는 세부 내용에서 몇 가지 선택 사항을 설명합니다. 이하 글에서는 몇 가지 운영체제에서 장고를 설치 및 설정하는 방법을 보여주고, 나머지 튜토리얼에서는 모두 이 설정을 가정해서 진행됩니다.</p> + +<div class="note"> +<p><strong>주의</strong>: 공식 장고 문서에서 다른 설치 옵션을 찾을 수 있습니다. 링크 : <a href="#furtherreading">appropriate documents below</a>.</p> +</div> + +<h4 id="어떤_운영체제가_지원되나요">어떤 운영체제가 지원되나요?</h4> + +<p>장고는 파이썬 3 프로그래밍 언어를 실행할 수 있는 거의 모든 기계에서 실행될 수 있습니다: 윈도우, 맥 OS X, 리눅스/유닉스, 솔라리스 등등. 거의 모든 컴퓨터가 개발 중에 장고를 실행할 수 있는 성능을 갖고 있습니다.</p> + +<p>이 글에서는 윈도우, 맥 OS X, 리눅스/유닉스에 관해 설명하도록 하겠습니다.</p> + +<h4 id="파이썬은_어느_버전을_사용해야_할까">파이썬은 어느 버전을 사용해야 할까?</h4> + +<p>가능한 최신 버전을 사용할 것을 권장합니다. 이 글을 작성할 때 가장 최신 버전은 파이썬 3.7입니다.</p> + +<p>필요에 따라 Python 3.4 혹은 그 이후의 버전이 사용될 수 있습니다. (파이썬 3.4는 차후에 지원이 안될 수도 있습니다)</p> + +<div class="note"> +<p><strong>주의</strong>: 파이썬 2.7은 장고 2.0에서 사용할 수 없습니다. (장고 1.11.x 버전에서 마지막으로 파이썬 2.7을 지원했습니다)</p> +</div> + +<h4 id="장고는_어디서_다운로드할_수_있나요">장고는 어디서 다운로드할 수 있나요?</h4> + +<p>장고를 다운로드하는 세가지 방법 :</p> + +<ul> + <li>pip 도구를 이용한 PyPi(Python Package Repository)에서 설치. 이 방법이 장고의 최신 버전을 받을 수 있는 최적의 방법입니다.</li> + <li>본인 컴퓨터의 패키지 매니저에 있는 버전을 사용하세요. 운영체제와 함께 제공되는 장고는 친숙한 설치 방법을 제공합니다. 다만 이것은 상당히 오래된 버전일 것이며, (아마 그렇게 원하지 않을) 시스템 파이썬 환경에만 설치될 수 있다는 것에 유의하세요.</li> + <li>소스에서 설치하기. 소스에서 장고의 최신버전을 다운로드하여 설치할 수 있습니다. 초심자에게는 추천하지 않지만, 당신이 장고에게 기여할 수 있는 준비가 됐다면 필요합니다.</li> +</ul> + +<p>아래 글은 최신의 안정된 버전을 얻기 위해 PyPi에서 장고를 설치하는 방법을 보여줍니다.</p> + +<h4 id="어떤_Database를_써야_하나요">어떤 Database를 써야 하나요?</h4> + +<p>장고는 네 가지 메인 데이터베이스(PostgreSQL, MySQL, Oracle 그리고 SQLite)를 지원합니다. 그리고 다른 인기있는 SQL과 NoSQL 데이터베이스들을 다양한 레벨로 지원하는 커뮤니티 라이브러리가 있습니다. 우리는 생산과 개발에 동일한 데이터베이스를 선택하는 것을 추천합니다(장고는 ORM(Object-Relational Mapper)을 사용해 데이터베이스간의 차이 대부분을 추상화하긴 하지만, 아직 피하는게 나은 <a href="https://docs.djangoproject.com/en/2.0/ref/databases/">잠재적 문제들</a>이 있습니다.</p> + +<p>이 글에서(그리고 이 모듈의 거의 모든 부분에서) 우리는 데이터를 파일로 저장하는 SQLite 데이터베이스를 사용할 것 입니다. SQLite는 가벼운 데이터베이스로 사용하기에 적합하며 높은 수준의 동시성을 지원하지 않습니다. 그렇지만 주로 읽기 전용인 응용 프로그램을 위해서는 아주 좋은 선택입니다.</p> + +<div class="note"> +<p><strong>주의</strong>: 장고는 <em>django-admin과 같이 웹사이트를 만드는 표준 도구를 사용하면</em> SQLite가 기본 값으로 설정되어 있습니다. 이는 추가적인 설정이 필요하지 않으므로 시작하기에 좋습니다. </p> +</div> + +<h4 id="시스템_전체에_설치할까요_파이썬_가상환경에_설치할까요">시스템 전체에 설치할까요, 파이썬 가상환경에 설치할까요?</h4> + +<p>파이썬 3를 설치하면 모든 파이썬 3 코드가 공유하는 하나의 글로벌 환경이 만들어집니다. 그 환경에 원하는 어떤 파이썬 패키지라도 설치할 수 있지만, 각 패키지의 하나의 버전만 설치할 수 있습니다.</p> + +<div class="note"> +<p><strong>주의</strong>: 글로벌 환경에 설치된 파이썬 응용 프로그램들은 서로 충돌할 가능성이 있습니다. (예: 같은 패키지의 다른 버전일 경우)</p> +</div> + +<p>만약 장고를 기본/전역 환경에 설치한다면 컴퓨터에서 하나의 장고 버전만을 대상으로 지정할 수 있습니다. 이것은 당신이 옛날 버전으로 작동하는 웹사이트를 관리하면서 최신 버전의 장고를 이용한 새로운 웹사이트를 만들고 싶을 때 문제가 됩니다.</p> + +<p>결과적으로, 경험있는 파이썬/장고 개발자들은 일반적으로 독립적인 파이썬 환경에서 파이썬 앱들을 실행합니다. 이것은 여러 다른 장고 환경이 하나의 컴퓨터에서 작동 가능하게 합니다. 장고 개발팀에서도 당신이 파이썬 가상 환경을 사용하는 것을 추천합니다!</p> + +<p>이 모듈은 당신이 장고를 가상 환경에 설치했다고 가정합니다. 아래에서 어떻게 설치하는지 알려드리겠습니다.</p> + +<h2 id="파이썬_3_설치">파이썬 3 설치</h2> + +<p>장고를 사용하기 위해서 파이썬을 설치해야 합니다. 파이썬 3을 사용하는 경우 장고와 다른 파이썬 앱에서 사용하는 파이썬 패키지 및 라이브러리를 설치, 업데이트, 제거하는 데 사용되는 <a href="https://pypi.org/">pip3 (Python Package Index)</a> 도구도 필요합니다.</p> + +<p>이번 섹션에서는 현재 당신의 파이썬 버전이 무엇인지 확인하고, 필요에 따라 운영체제(Ubuntu Linux 16.04, macOS X, and Windows 10)별로 새로운 버전 설치 방법을 간단하게 설명합니다.</p> + +<div class="note"> +<p><strong>주의</strong>: 플랫폼에 따라 운영 체제의 자체 패키지 관리자 또는 다른 메커니즘을 통해 Python / pip를 설치할 수도 있습니다. 대부분의 플랫폼의 경우 <a href="https://www.python.org/downloads/">https://www.python.org/downloads/</a>에서 필요한 설치 파일을 다운로드하여 적절한 플랫폼 별 방법을 사용하여 설치할 수 있습니다.</p> +</div> + +<h3 id="우분투_16.04">우분투 16.04</h3> + +<p>우분투 리눅스 18.04 LTS는 파이썬 3.6.6을 기본적으로 포함하고 있습니다. bash 터미널에서 아래 코드를 실행하여 이것을 확인할 수 있습니다.:</p> + +<pre class="brush: bash notranslate"><span style="line-height: 1.5;">python3 -V + Python 3.6.6</span></pre> + +<p>그러나 파이썬3의 패키지 설치를 위한 Python Package Index tool(장고를 포함해)는 기본적으로 설치되어있지 않습니다. bash 터미널에서 아래 코드를 사용하여 pip3를 설치할 수 있습니다:</p> + +<pre class="brush: bash notranslate">sudo apt install python3-pip +</pre> + +<h3 id="맥OS_X">맥OS X</h3> + +<p>맥OS X "엘 캐피탄" 이후의 최신 버전에서는 파이썬3를 포함하고 있지 않습니다. bash 터미널에서 아래 코드를 실행해서 확인할 수 있습니다.:</p> + +<pre class="brush: bash notranslate"><span style="line-height: 1.5;">python3 -V + </span>-bash: python3: command not found</pre> + +<p>당신은<a href="https://www.python.org/"> python.org</a>에서 파이썬3를(pip3 도구도 함께) 쉽게 설치할 수 있습니다:</p> + +<ol> + <li>필요한 설치 파일을 다운로드하세요: + <ol> + <li><a href="https://www.python.org/downloads/">https://www.python.org/downloads/</a> 로 가세요.</li> + <li><strong>Download Python 3.7.0</strong> 버튼을 선택하세요 (정확한 마이너 버전 숫자는 다를 수도 있습니다).</li> + </ol> + </li> + <li>파인더를 통해 파일을 찾아, 패키지 파일을 더블클릭 하세요. 그리고선 설치 과정을 따릅니다.</li> +</ol> + +<p>이제 아래와 같이 파이썬3의 성공적인 설치를 확인할 수 있습니다:</p> + +<pre class="brush: bash notranslate"><span style="line-height: 1.5;">python3 -V + Python 3.7.0</span> +</pre> + +<p>가능한 패키지들의 목록을 불러옴으로써 pip3가 설치된 것을 확인할 수 있습니다:</p> + +<pre class="brush: bash notranslate">pip3 list</pre> + +<h3 id="윈도우_10">윈도우 10</h3> + +<p>윈도우는 파이썬을 기본적으로 포함하고 있지 않지만, <a href="https://www.python.org/">python.org</a>에서(pip3 도구와 함께) 쉽게 설치할 수 있습니다:</p> + +<ol> + <li>필요한 설치 파일을 다운로드하세요: + <ol> + <li><a href="https://www.python.org/downloads/">https://www.python.org/downloads/</a> 로 가세요</li> + <li><strong>Download Python 3.7.1 </strong>버튼을 선택하세요 (정확한 마이너 버전 숫자는 다를 수도 있습니다).</li> + </ol> + </li> + <li>다운로드된 파일을 더블클릭해서 파이썬을 설치하세요.</li> +</ol> + +<p>명령 프롬프트에서 아래 텍스트를 입력해서 파이썬3가 설치된 것을 확인할 수 있습니다:</p> + +<pre class="brush: bash notranslate"><span style="line-height: 1.5;">py -3 -V + Python 3.7.1</span> +</pre> + +<p>윈도우 버전의 설치 파일은 pip3(파이썬 패키지 관리자)가 기본적으로 포함되어 있습니다. 아래 코드로 설치된 패키지 목록을 볼 수 있습니다.</p> + +<pre class="brush: bash notranslate"><span style="line-height: 1.5;">pip3 list</span> +</pre> + +<div class="note"> +<p><strong>주의</strong>: 설치 파일은 위 코드들이 실행되기 위한 모든 것을 설치해줄 것입니다. 만약 파이썬을 찾을 수 없다는 메시지가 나오면, 파이썬을 당신의 시스템 경로에 추가하는 것을 깜빡했을 수가 있습니다. 당신은 설치 파일을 다시 실행해서 'Modify'를 선택 후 두 번째 페이지에 있는 "Add Python to environment variables" 박스에 체크함으로써 시스템 경로에 파이썬을 추가할 수 있습니다.</p> +</div> + +<h2 id="파이썬_가상_환경에서_장고_사용하기">파이썬 가상 환경에서 장고 사용하기</h2> + +<p>우리가 가상 환경을 만드는 데 사용할 라이브러리들은 <a href="https://virtualenvwrapper.readthedocs.io/en/latest/index.html">virtualenvwrapper</a> (리눅스와 맥 OS X) 그리고 <a href="https://pypi.python.org/pypi/virtualenvwrapper-win">virtualenvwrapper-win</a> (윈도우)입니다. 둘 다 <a href="https://developer.mozilla.org/en-US/docs/Python/Virtualenv">virtualenv</a> 도구를 사용하죠. wrapper 도구는 모든 플랫폼의 인터페이스를 관리하기 위한 일관적인 인터페이스를 생성합니다.</p> + +<h3 id="가상_환경_소프트웨어_설치하기">가상 환경 소프트웨어 설치하기</h3> + +<h4 id="우분투_가상_환경_셋업">우분투 가상 환경 셋업</h4> + +<p>파이썬과 pip를 설치한 후에 (virtualenv를 포함하는)virtualenvwrapper를 설치할 수 있습니다. 공식 설치 가이드는 <a href="http://virtualenvwrapper.readthedocs.io/en/latest/install.html">여기</a>엣서 찾을 수 있습니다. 아니면 아래 설명을 따라오세요.</p> + +<p>pip3를 사용해서 그 도구를 설치하세요:</p> + +<pre class="brush: bash notranslate"><code>sudo pip3 install virtualenvwrapper</code></pre> + +<p>그리고 당신의 shell 스타트업 파일(이것은 당신의 홈 디렉토리에 있는 숨겨진 <strong>.bashrc</strong> 파일 이름입니다)의 끝에 아래 코드를 추가하세요. 이 코드들은 가상 환경이 활동할 위치, 당신의 개발 프로젝트 디렉토리 위치, 그리고 이 패키지와 함께 설치된 스크립트의 위치를 설정합니다:</p> + +<pre class="brush: bash notranslate"><code>export WORKON_HOME=$HOME/.virtualenvs +export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3 +export VIRTUALENVWRAPPER_VIRTUALENV_ARGS=' -p /usr/bin/python3 ' +export PROJECT_HOME=$HOME/Devel +source /usr/local/bin/virtualenvwrapper.sh</code></pre> + +<div class="note"> +<p><strong>Note</strong>:<code>VIRTUALENVWRAPPER_PYTHON</code> 와 <code>VIRTUALENVWRAPPER_VIRTUALENV_ARGS </code>변수는 파이썬3의 일반적인 설치 위치를 가리킵니다. 그리고 <code>source /usr/local/bin/virtualenvwrapper.sh</code> 는 <code>virtualenvwrapper.sh</code> 스크립트의 일반적인 위치를 가리킵니다. 만약 테스트 중에 virtualenv가 작동하지 않는다면, 확인해야 할 일 중 하나는 파이썬과 스크립트가 알맞은 위치에 있는지 입니다(그리고 스타트업 파일을 그에 맞게 바꾸세요).<br> + <br> + <code>which virtualenvwrapper.sh</code> 와 <code>which python3</code>커맨드를 사용해서 당신의 시스템에 알맞은 위치를 찾을 수 있습니다.</p> +</div> + +<p>그리고 아래 코드를 터미널에서 실행하여 스타트업 파일을 다시 불러오세요:</p> + +<pre class="brush: bash notranslate"><code>source ~/.bashrc</code></pre> + +<p>이 시점에서 아래와 같이 한 다발의 스크립트가 실행되는 걸 볼 수 있습니다 :</p> + +<pre class="brush: bash notranslate"><code>virtualenvwrapper.user_scripts creating /home/ubuntu/.virtualenvs/premkproject +virtualenvwrapper.user_scripts creating /home/ubuntu/.virtualenvs/postmkproject +... +virtualenvwrapper.user_scripts creating /home/ubuntu/.virtualenvs/preactivate +virtualenvwrapper.user_scripts creating /home/ubuntu/.virtualenvs/postactivate +virtualenvwrapper.user_scripts creating /home/ubuntu/.virtualenvs/get_env_details</code></pre> + +<p>이제 <code>mkvirtualenv</code>명령으로 새로운 가상 환경을 생성할 수 있습니다.</p> + +<h4 id="맥OS_X_가상_환경_설정">맥OS X 가상 환경 설정</h4> + +<p>맥OS X에서 <em>virtualenvwrapper</em>를 설정하는 것은 우분트와 거의 다를바가 없습니다. (다시 말하지만, <a href="http://virtualenvwrapper.readthedocs.io/en/latest/install.html">공식 설치 가이드</a> 를 따라하거나 아래 내용을 따라해도 됩니다).</p> + +<p>아래와 같이 pip를 이용해 <em>virtualenvwrapper</em> (와 동봉된 <em>virtualenv</em>)를 설치하세요.</p> + +<pre class="brush: bash notranslate"><code>sudo pip3 install virtualenvwrapper</code></pre> + +<p>그리고 쉘 시작 파일(shell startup file)의 맨 아랫쪽에 아래 코드를 추가하세요.</p> + +<pre class="brush: bash notranslate"><code>export WORKON_HOME=$HOME/.virtualenvs +export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3 +export PROJECT_HOME=$HOME/Devel +source /usr/local/bin/virtualenvwrapper.sh</code> +</pre> + +<div class="note"> +<p><strong>참고사항</strong>: <code>VIRTUALENVWRAPPER_PYTHON</code> 변수는 파이썬3의 일반적인 설치 위치를 가리키며, <code>source /usr/local/bin/virtualenvwrapper.sh</code>는 <code>virtualenvwrapper.sh</code>스크립트의 일반적인 위치를 가리킵니다. 당신이 테스트할 때 <em>virtualenv</em> 가 동작하지 않는다면, 한가지 체크해볼 것은 파이썬과 해당 스크립트가 위에서 가리키는 위치에 있는지 여부입니다( 다르다면 startup 파일을 적절하게 수정해야 합니다).</p> + + + +<p>예를 들어, 맥OS상의 어떤 시스템의 설치 테스트에서는 startup 파일에 아래와 같은 코드를 추가할 필요가 있었습니다 :</p> + +<pre class="notranslate"><code>export WORKON_HOME=$HOME/.virtualenvs +export VIRTUALENVWRAPPER_PYTHON=/Library/Frameworks/Python.framework/Versions/3.7/bin/python3 +export PROJECT_HOME=$HOME/Devel +source /Library/Frameworks/Python.framework/Versions/3.7/bin/virtualenvwrapper.sh</code></pre> + +<p><code>which virtualenvwrapper.sh</code>와 <code>which python3</code>.명령을 이용하여 당신 시스템 환경에서의 정확한 위치를 찾을 수 있습니다.</p> + + +</div> + +<p>이 코드들은 우분트에서도 같은 코드이지만, startup 파일은 당신의 홈 디렉토리에 위치하며 다른 이름 <strong>.bash_profile</strong>을 가진 숨겨진 파일입니다.</p> + +<div class="note"> +<p><strong>Note</strong>: 파인더(finder)에서<strong>.bash-profile</strong> 파일을 찾을 수 없다면, 터미널에서 nano를 이용해 이 파일을 열 수 있습니다. </p> + +<p>터미널 명령은 대체로 아래와 같습니다 :</p> + +<pre class="notranslate"><code>cd ~ # Navigate to my home directory +ls -la #List the content of the directory. YOu should see .bash_profile +nano .bash_profile # Open the file in the nano text editor, within the terminal +# Scroll to the end of the file, and copy in the lines above +# Use Ctrl+X to exit nano, Choose Y to save the file.</code> +</pre> + + +</div> + +<p>그 다음엔, 터미널에서 아래 명령을 호출하여 startup 파일을 재실행 하세요 :</p> + +<pre class="brush: bash notranslate"><code>source ~/.bash_profile</code></pre> + +<p>이 시점에서 한 다발의 스크립트가 실행되는 걸 볼 수 있습니다( Ubuntu 설치때와 같은 스크립트 입니다). 이제 <code>mkvirtualenv</code> 명령으로 새로운 가상환경을 생성할 수 있어야 합니다.</p> + +<h4 id="윈도우_10_가상_환경_설정">윈도우 10 가상 환경 설정</h4> + +<p><a href="https://pypi.python.org/pypi/virtualenvwrapper-win">virtualenvwrapper-win</a> 를 설치하는것이 virtualenvwrapper를 설치하는 것보다 훨씬 쉬운데, 가상 환경 정보를 어디에 저장해야할지 설정할 필요가 없기 때문입니다 (기본값이 있습니다). 아래 명령을 명령 프롬프트에서 실행하는 것이 당신이 해야할 전부입니다:</p> + +<pre class="notranslate"><code>pip3 install virtualenvwrapper-win</code></pre> + +<p>이제 <code>mkvirtualenv</code> 명령으로 새로운 가상환경을 생성할 수 있습니다.</p> + +<h3 id="가상_환경_생성하기">가상 환경 생성하기</h3> + +<p>일단 virtualenvwrapper 나 virtualenvwrapper-win 을 설치했다면 가상 환경으로 작업하는 것은 모든 플랫폼별에서 차이가 거의 없습니다.</p> + +<p>이제 mkvirtualenv 명령으로 새로운 가상 환경을 생성할 수 있습니다. 이 명령이 수행될 때 환경이 설정되는 과정을 보게됩니다( 플랫폼에 따라 보이는 것이 다릅니다). 명령이 완료되면 새로운 가상환경이 활성화 됩니다 — 괄호내에 있는 가상환경의 이름으로 프롬프트가 시작하는 것으로 알 수 있습니다 (아래는 우분투의 경우인데, 마지막 라인은 윈도우/맥OS 도 유사합니다).</p> + +<pre class="notranslate"><code>$ mkvirtualenv my_django_environment + +Running virtualenv with interpreter /usr/bin/python3 +... +virtualenvwrapper.user_scripts creating /home/ubuntu/.virtualenvs/t_env7/bin/get_env_details +(my_django_environment) ubuntu@ubuntu:~$</code> +</pre> + +<p>이제 당신은 가상환경내에 있으며 장고를 설치하고 개발을 시작할 수 있습니다.</p> + +<div class="note"> +<p><strong>주의</strong>: 이 시점부터 이 기사 ( 정확히는 이 모듈)에서 실행되는 모든 명령은 위에서 우리가 설정한 파이썬 가상환경내에서 실행되는 것으로 간주합니다.</p> +</div> + +<h3 id="가상_환경_사용하기">가상 환경 사용하기</h3> + +<p>당신이 알아야 하는 명령이 몇 가지 더 있다.(도구 문서에는 더 많이 있긴하지만, 아래 명령이 꾸준히 사용하게될 명령들이다):</p> + +<ul> + <li><code>deactivate</code> — 활성화된 파이썬 가상 환경을 비활성화한다</li> + <li><code>workon</code> — 사용가능한 가상 환경 목록을 보여준다</li> + <li><code>workon name_of_environment</code> — 특정 파이썬 가상 환경을 활성화한다</li> + <li><code>rmvirtualenv name_of_environment</code> — 특정 환경을 제거한다.</li> +</ul> + +<h2 id="장고_설치하기">장고 설치하기</h2> + +<p>일단 가상 환경을 하나 생성하고, 진입하기 위해 <code>workon</code> 을 호출하면 장고를 설치하기 위해 pip3를 사용할 수 있다. </p> + +<pre class="brush: bash notranslate">pip3 install django +</pre> + +<p>아래 명령을 실행하여 장고가 설치되었는지 테스트할 수 있다 (이 명령은 단지 파이썬이 django 모듈을 찾을 수 있는지 테스트한다):</p> + +<pre class="brush: bash notranslate"># Linux/macOS X +python3 -m django --version + 2.0 + +# Windows +py -3 -m django --version + 2.0 +</pre> + +<div class="note"> +<p><strong>주의</strong>: 위의 윈도우 명령이 django 모듈이 존재하는지 보여주지 않으면, 아래 명령을 시도해보세요:</p> + +<pre class="notranslate"><code>py -m django --version</code></pre> + +<p>당신의 설치 방법에 따라 변할수도 있긴 하지만, 윈도우에서는 파이썬 3 스트립트는 <code>py -3</code>을 명령앞에 붙여야 실행됩니다. 명령 실행에 문제가 있으면 <code>-3</code>옵션을 빼 보세요. 리눅스/맥OS X 에서는 <code>python3</code>명령입니다.</p> +</div> + +<div class="warning"> +<p><strong>중요사항</strong>: 이 <strong>모듈</strong> 의 나머지부분에서는 파이썬 3를 실행하는 명령으로 리눅스 명령 (<code>python3</code>) 을 사용합니다. 당신이 윈도우에서 진행중이라면 단지 명령 앞부분을 <code>py -3</code>로 변경하면 됩니다.</p> +</div> + +<h2 id="설치한_것_확인하기">설치한 것 확인하기</h2> + +<p>위 테스트는 성공해도 그리 재미있는 작업은 아니었습니다. 더 흥미있는 테스트는 기초적인 프로젝트를 생성해서 동작하는것을 보는것입니다. 이것을 해보기 위해, 명령 프롬프트/터미널에서 장고 앱을 저장할 부모폴더로 이동하세요. 테스트 사이트용 폴더를 생성하고 그 폴더안으로 이동하세요.</p> + +<pre class="brush: bash notranslate">mkdir django_test +cd django_test +</pre> + +<p>그 다음 아래와 같이 <strong>django-admin</strong> 도구를 이용해 "<em>mytestsite</em>" 라는 사이트의 기본 토대를 생성할 수 있습니다. 사이트를 생성한 이후 그 폴더로 가면 해당 프로젝트를 관리할수 있는 <strong>manage.py</strong> 라는 이름의 메인 스크립트파일을 발견할 것입니다.</p> + +<pre class="brush: bash notranslate">django-admin startproject mytestsite +cd mytestsite</pre> + +<p>이 폴더내에서 <code>runserver</code> 명령과 <strong>manage.py</strong> 를 이용하여 아래와 같이 개발용 웹 서버를 실행할 수 있습니다.</p> + +<pre class="brush: bash notranslate">$ python3 manage.py runserver +Performing system checks... + +System check identified no issues (0 silenced). + +You have 15 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions. +Run 'python manage.py migrate' to apply them. + +October 26, 2018 - 07:06:30 +Django version 2.1.2, using settings 'mytestsite.settings' +Starting development server at http://127.0.0.1:8000/ +Quit the server with CONTROL-C. +</pre> + +<div class="note"> +<p><strong>주의</strong>: 위 명령은 Linux/macOS X 명령을 보여준다. 지금 시점에서는 "15 unapplied migration(s)" 의 경고 문구는 무시해도 됩니다 !</p> +</div> + +<p>일단 서버가 실행중이면 당신 시스템의 웹 브라우저로 아래 URL에 가서 만들어진 사이트를 볼 수 있습니다: <code>http://127.0.0.1:8000/</code>. 방문한 사이트에서 아래와 같은 모습이 보여야 합니다:</p> + +<p><img alt="Django Skeleton App Homepage" src="https://mdn.mozillademos.org/files/15728/Django_Skeleton_Website_Homepage.png"></p> + +<ul> +</ul> + +<h2 id="요약">요약</h2> + +<p>당신은 이제 장고 개발 환경을 구축하고 당신의 컴퓨터에서 실행중입니다.</p> + +<p>마지막 확인 섹션에서 <code>django-admin startproject</code> 명령을 이용해 어떻게 새로운 장고 웹사이트를 생성할 수 있는지 간단하게 확인했습니다. 그리고 개발용 웹 서버를 이용해 당신의 브라우저로 웹사이트를 실행했습니다(<code>python3 manage.py runserver</code>). 다음 튜토리얼에서는 간단하지만 완전한 웹 어플리케이션을 구축하는 이 과정을 좀 더 상세히 설명합니다.</p> + +<h2 id="더불어_보기">더불어 보기</h2> + +<ul> + <li><a href="https://docs.djangoproject.com/en/2.0/intro/install/">빠른 설치 가이드</a> (Django 문서)</li> + <li><a href="https://docs.djangoproject.com/en/2.0/topics/install/">Django 설치하는 법 — 완벽 가이드</a> (Django 문서) - Django를 제거하는 방법도 포함됨</li> + <li><a href="https://docs.djangoproject.com/en/2.0/howto/windows/">윈도우에 장고 설치하기</a> (Django 문서)</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Django/Introduction", "Learn/Server-side/Django/Tutorial_local_library_website", "Learn/Server-side/Django")}}</p> + +<h2 id="이_모듈에_포함된_튜토리얼">이 모듈에 포함된 튜토리얼</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Server-side/Django/Introduction">Django introduction</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/development_environment">Setting up a Django development environment</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Django Tutorial: The Local Library website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django Tutorial Part 2: Creating a skeleton website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Models">Django Tutorial Part 3: Using models</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Admin_site">Django Tutorial Part 4: Django admin site</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django Tutorial Part 5: Creating our home page</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Generic_views">Django Tutorial Part 6: Generic list and detail views</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Sessions">Django Tutorial Part 7: Sessions framework</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Authentication">Django Tutorial Part 8: User authentication and permissions</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Forms">Django Tutorial Part 9: Working with forms</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Testing">Django Tutorial Part 10: Testing a Django web application</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Django Tutorial Part 11: Deploying Django to production</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/web_application_security">Django web application security</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></li> +</ul> diff --git a/files/ko/learn/server-side/django/forms/index.html b/files/ko/learn/server-side/django/forms/index.html new file mode 100644 index 0000000000..e8b51c3bf5 --- /dev/null +++ b/files/ko/learn/server-side/django/forms/index.html @@ -0,0 +1,682 @@ +--- +title: 'Django 튜토리얼 파트 9: 폼(form)으로 작업하기' +slug: Learn/Server-side/Django/Forms +translation_of: Learn/Server-side/Django/Forms +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Django/authentication_and_sessions", "Learn/Server-side/Django/Testing", "Learn/Server-side/Django")}}</div> + +<p class="summary">이 튜토리얼에서 우리는 Django에서 HTML Form 작업 방법을 보여주고 특히 model Instance를 생성,수정,제거 하는 Form을 작성하는 가장 쉬운 방법을 보여줄 것이다. 이 예제의 일부분으로 우리는 도서관직원이 (admin 앱을 이용하기 보다) 우리가 만든 form을 이용하여 책 대여기간을 연장하거나 작가 정보를 생성,수정,제거할 수 있도록 <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a> 웹사이트를 확장할 것이다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">사전학습:</th> + <td>아래 파트를 포함하여 앞선 모든 튜토리얼 파트의 학습을 완료할것 <a href="/en-US/docs/Learn/Server-side/Django/authentication_and_sessions">Django 튜토리얼 파트 8: 사용자 인증과 이용권한</a>.</td> + </tr> + <tr> + <th scope="row">학습목표:</th> + <td>사용자로 부터 정보를 얻고 database를 수정하는 form을 작성하는 방법을 이해하기. 일반 클래스 기반 form 편집용 view가 단독 model로 동작하는 form을 작성할 때 얼마나 많이 단순화할 수 있는지 이해하기. </td> + </tr> + </tbody> +</table> + +<h2 id="개요">개요</h2> + +<p><a href="/ko/docs/Web/Guide/HTML/Forms">HTML 폼(Form)</a> 은 웹 페이지상에서 한개 이상의 필드나 위젯들의 묶음을 말하며, 사용자로부터 정보를 수집하여 서버에 제출하는데 사용된다. 다양한 종류의 데이타 입력을 지원하는 위젯들( 텍스트 박스, 체크 박스, 라디오 버튼, 날짜 선택기 등등)이 많이 존재하기 때문에, 폼은 사용자 입력을 수집하는데 유연한 장치라고 할 수 있다. 폼은 또한, 교차 사이트 요청 위조 방지(CSRF protection, cross-site request forgery protection)와 함께 <code>POST</code>요청으로 데이타를 보낼수 있도록 지원하므로, 데이타를 서버와 공유하는데 있어서 비교적 안전한 방법이다.</p> + +<p>지금까지 이 튜토리얼에서 우리가 직접 폼을 생성한 적은 없지만, Django 관리 사이트에서 이미 경험해 보았다. 예를 들면, 아래 스크린 샷에서 <a href="/ko/docs/Learn/Server-side/Django/Models">Book</a> 모델중 하나를 편집하는 폼을 보여주고 있는데, 몇개의 선택 목록과 텍스트 에디터를 볼 수 있다.</p> + +<p><img alt="Admin Site - Book Add" src="https://mdn.mozillademos.org/files/13979/admin_book_add.png" style="border-style: solid; border-width: 1px; display: block; margin: 0px auto;"></p> + +<p>폼을 개발하는 것은 복잡한 작업이 될수도 있다! 개발자는 일단, 폼을 위한 HTML을 작성해야 하며, 서버로 입력된 (아마도 브라우저로도 입력된) 데이타의 유효성을 검증하고 적절하게 수정하도록 하고, 유효하지 않은 입력에 대해서 사용자가 알 수 있도록 폼을 에러 메시지와 함께 다시 표시해야하며,성공적으로 제출된 데이타를 적절히 처리하고, 마지막으로 성공했을 경우 사용자가 알수 있게 응답하도록 개발 해야 한다. <em>Django 폼은 다음과 같은 기능의 프레임워크를 제공하여 이 모든 단계중 많은 부분을 덜어내 준다. 이 프레임워크는 폼과 그에 연관된 필드를 프로그램적으로 정의하여 객체를 만들고, 폼 HTML 코드를 작성하는 작업과 데이타 유효성 검증과 사용자 상호작용에 이 객체들을 사용한다.</em></p> + +<p>이번 튜토리얼에서는, 폼을 생성하고 폼으로 작업하는 몇가지 방법을 보여줄 것이다. 특히, 모델을 처리하는 폼을 작성하는데 필요한 작업량을, generic 편집 폼 view를 이용하여 어떻게 획기적으로 줄일 수 있는지 보여줄 것이다. 그 과정에서, 도서관 사서들이 도서관 책 상태를 갱신할 수 있는 폼을 추가하고 책과 저자를 생성, 편집, 삭제할수 있는 페이지를 생성할 것이다. (즉, 위와 같이 책을 편집하는 폼의 기본적인 버전을 다시 개발하는 것이다).</p> + +<h2 id="HTML_폼Form_이란">HTML 폼(Form) 이란?</h2> + +<p>첫번째로 <a href="/en-US/docs/Learn/HTML/Forms">HTML 폼(Form</a>)에 대한 간단한 개요이다. 어떤 "team"의 이름을 입력하는 단일 텍스트 필드와 관련 라벨을 가진 간단한 HTML 폼을 생각해보자:</p> + +<p><img alt="Simple name field example in HTML form" src="https://mdn.mozillademos.org/files/14117/form_example_name_field.png" style="border-style: solid; border-width: 1px; display: block; height: 44px; margin: 0px auto; width: 399px;"></p> + +<p>폼은 HTML에서 적어도 한 개 이상의 <code>type="submit"</code>인 <code>input</code> 요소를 포함하는 <code><form>...</form></code> 태그 사이의 요소들의 집합으로 정의된다.</p> + +<pre class="brush: html"><form action="/team_name_url/" method="post"> + <label for="team_name">Enter name: </label> + <input id="team_name" type="text" name="name_field" value="Default name for team."> + <input type="submit" value="OK"> +</form></pre> + +<p>위 코드에서는 팀 이름을 입력하기 위한 텍스트 필드를 단지 한개만 가지는데, 폼이 가질수 있는 입력 요소와 관련 라벨의 갯수에는 제한이 없다. 필드의 <code>type</code> 속성은 어떤 종류의 위젯이 표시될지 정의한다. 필드의 <code>name</code>과 <code>id</code> 가 JavaScript/CSS/HTML에 있는 필드를 확인하는데 사용되고 <code>value</code>는 필드가 처음 표시될 때의 초기값을 정의한다. 관련 팀 라벨은 <code style="font-style: normal; font-weight: normal;">label</code>태그( 위 코드에서 "Enter name"을 확인)를 이용해 명시된다. 여기서 <code style="font-style: normal; font-weight: normal;">for</code>필드는 관련된 <code style="font-style: normal; font-weight: normal;">input</code>의 <code style="font-style: normal; font-weight: normal;">id</code>값을 포함하고 있다. </p> + +<p><code>submit</code> 타입의 input 태그는 (기본적으로) 사용자가 누를수 있는 버튼으로 표시되는데, 버튼의 동작에 의해 폼의 다른 모든 input 요소의 데이터가 서버로 업로드된다 (위의 경우는 <code>team_name</code>만 업로드된다). 폼 속성으로는 데이터를 보내기 위해 사용되는 HTTP <code>method</code>와 서버상에서 데이타의 목적지를 ( <code>action</code>으로) 정의한다:</p> + +<ul> + <li><code>action</code>: 폼이 제출(submit)될 때 처리가 필요한 데이타를 전달받는 곳의 자원/URL 주소. 설정이 안되면 (혹은 빈 문자열로 설정되면), 폼은 현재 페이지 URL로 다시 제출된다.</li> + <li><code>method</code>: 데이터를 보내는데 사용되는 HTTP 메소드: <em>post</em> 이거나 <em>get 이다.</em> + <ul> + <li><code>POST</code> 메소드는 사이트간 요청 위조 공격에 좀 더 저항성이 좋게 만들 수 있기 때문에, 관련 데이터에 의해 서버 데이터베이스가 변경될 경우에는 항상 사용 되어야 한다. </li> + <li><code>GET</code> 메소드는 사용자 데이터를 변경하지 않는 폼(예를 들면 , 탐색 폼)에서만 사용되어야 한다. URL을 북마크하길 원하거나 공유하기를 원하는 경우에 추천한다. </li> + </ul> + </li> +</ul> + +<p>서버의 역할은 첫번째로 - 필드를 비워두거나 초기값으로 채워두도록 - 초기 폼 상태를 표시하는 것이다. 사용자가 제출 버튼을 누른후에, 서버는 웹 브라우저로부터 폼의 데이타를 념겨 받고, 데이타의 유효성 검증을 해야한다. 폼이 유효하지 않은 데이타를 담고 있다면, 서버는 폼을 다시 표기해야 하는데, 이번에는 사용자가 입력한 유효한 데이타는 그대로 표시하며, 유효하지 않은 필드만 경고 메시지와 함께 표기해야 한다. 일단 모든 필드의 데이타가 유효한 폼 데이타의 제출요청을 서버가 받게 되면, 서버는 적절한 동작(예를 들면, 데이타를 저장하거나, 검색결과를 반화하거나, 파일을 업로딩하는 등등의 작업)을 수행하고 사용자에게 알려주게된다.</p> + +<p>당신이 상상할 수 있듯이, HTML을 작성하고, 입력된 데이타의 유효성을 검증하고, 필요시에 입력된 데이타를 검증 결과와 함게 다시 표시하며, 유효한 데이타에 대해 요구되는 동작을 수행하는 것은 "올바르게 하기"위해서는 꽤 많은 노력이 필요한 작업이다. Django는 일부 과중한 작업과 반복 코드를 줄여줌으로서, 이 작업을 훨씬 쉽게 만든다!</p> + +<h2 id="Django_폼_처리_과정">Django 폼 처리 과정</h2> + +<p>Django의 폼 처리 과정은 (모델에 대한 정보를 보여주는데 있어서) 우리가 앞선 튜토리얼에서 배웠던 것과 같은 기술을 사용한다. : 뷰는 요청을 받고, 모델로 부터 데이타를 읽는것을 포함한 요구되는 동작을 수행한다. 그런 다음, (보여줄 데이타를 포함한 context를 전달받은 템플릿으로 부터) HTML page를 생성하고 반환한다. 서버 또한 사용자가 입력한 데이타를 처리가능 해야 하며, 에러가 있으면 그 페이지를 다시 보여줄 필요가 있기 때문에 상황을 더욱 복잡하게 만든다. </p> + +<p>아래에 Django가 어떻게 요청읕 처리하는지 보여주는 플로우 차트가 있다. 폼을 포함하는 페이지에 대한 요청 (초록색으로 표시함) 으로 시작하고 있다. </p> + +<p><img alt="Updated form handling process doc." src="https://mdn.mozillademos.org/files/14205/Form%20Handling%20-%20Standard.png" style="display: block; height: 569px; margin: 0px auto; width: 800px;"></p> + +<p>위의 다이어그램에 기반하여, Django 폼이 주요하게 다루는 것은 다음과 같다. :</p> + +<ol> + <li>사용자가 처음으로 폼을 요청할 때 기본 폼을 보여준다. + <ul> + <li>폼은 비어있는 필드가 있을 수 있다 (예를 들면, 새로운 책을 등록할 경우) 아니면 초기값으로 채워진 필드가 있을 수도 있다. ( 예를 들면, 기존의 책을 수정하거나, 흔히 사용하는 초기값이 있을경우)</li> + <li>이 시점의 폼은 (초기값이 있긴해도) 유저가 입력한 값에 연관되지 않았기에 unbound 상태라고 불린다.</li> + </ul> + </li> + <li>제출 요청으로 부터 데이타를 수집하고 그것을 폼에 결합한다. + <ul> + <li>데이타를 폼에 결합(binding) 한다는 것은 사용자 입력 데이타와 유효성을 위반한 경우의 에러메시지가 폼을 재표시할 필요가 있을 때 준비되었다는 의미이다.</li> + </ul> + </li> + <li>데이타를 다듬어서 유효성을 검증한다. + <ul> + <li>데이타를 다듬는다는 것은 사용자 입력을 정화(sanitisation) 하고 (예를 들면, 잠재적으로 악의적인 콘덴츠를 서버로 보낼수도 있는 유효하지 않은 문자를 제거하는 것) python에서 사용하는 타입의 데이타로 변환하는 것이다.</li> + <li>유효성검증은 입력된 값이 해당 필드에 적절한 값인지 검사한다. (예를 들면, 데이타가 허용된 범위에 있는 값인지, 너무 짧거나 길지 않은지 등등) </li> + </ul> + </li> + <li>입력된 어떤 데이타가 유효하지 않다면, 폼을 다시 표시하는데 이번에는 초기값이 아니라 유저가 입력한 데이타와 문제가 있는 필드의 에러 메시지와 함께 표시한다.</li> + <li>입력된 모든 데이타가 유효하다면, 요청된 동작을 수행한다. (예를 들면, 데이타를 저장하거나, 이메일을 보내거나, 검색결과를 반환하거나, 파일을 업로딩하는 작업 등등)</li> + <li>일단 모든 작업이 완료되었다면, 사용자를 새로운 페이지로 보낸다.</li> +</ol> + +<p>Django는 위에 설명된 작업을 도와줄 수많은 도구와 접근법을 제공한다. 가장 기초적인 것은 <code>Form</code> 클래스 인데 form HTML의 생성과 데이터 정화와 유효성검증을 간단하게 만든다. 다음 단계에서는, 도서관 사서가 책의 대여갱신을 할수 있도록 해주는 페이지의 실제적인 예제를 이용해 폼이 어떻게 동작하는지 살펴보도록 한다.</p> + +<div class="note"> +<p><strong>참고사항:</strong> <code>Form</code> 이 어떻게 사용되는지 이해해두면 Django의 "고급 레벨" 폼 프레임워크 클래스를 논의하는데 도움이 된다.</p> +</div> + +<h2 id="책_대여갱신_form과_함수_view">책 대여갱신 form과 함수 view</h2> + +<p>다음으로 도서관직원이 대여기간을 갱신할수 있는 페이지를 추가할 것이다. 이 작업을 위해 사용자가 날짜 정보를 입력할 수 있는 form을 생성할 것이다. 그 필드는 현재날짜로 부터 3주의 기간 (일반적인 대여기간)으로 초기화될 것이다. 그리고 도서관직원이 과거날짜를 입력하거나 너무 긴 대여기간을 입력하지 않도록 유효성 체크기능을 추가할 것이다. 유효 날짜가 입력되면, 현재 record의 <code>BookInstance.due_back</code> 필드에 써넣을 것이다.</p> + +<p>아래 예제는 함수기반 view와 <code>Form</code> 클래스를 이용할 것이다. 이어지는 내용에서 form 동작 방법과 현재진행중인 LocalLibray 프로젝트에서 변경할 내용을 설명한다.</p> + +<h3 id="Form_작성하기">Form 작성하기</h3> + +<p><code>Form</code> 클래스는 Django form 관리 시스템의 핵심이다. <code>Form</code> 클래스는 form내 field들, field 배치, 디스플레이 widget, 라벨, 초기값, 유효한 값과 (유효성 체크이후에) 비유효 field에 관련된 에러메시지를 결정한다. <code>Form</code> 클래스는 또한 미리 정의된 포맷(테이블, 리스트 등등) 의 템플릿으로 그자신을 렌더링하는 method나 (세부 조정된 수동 렌더링을 가능케하는) 어떤 요소의 값이라도 얻는 method를 제공한다.</p> + +<h4 id="Form_선언하기">Form 선언하기</h4> + +<p><code>Form</code> 을 선언하는 문법은 <code>Model</code>을 선언하는 것과 많이 닮았으며, 같은 필드타입을 사용한다. ( 또한 일부 매개변수도 유사하다) . 두가지 경우 모두 각 필드가 데이타에 맞는 (유효성 규칙에 맞춘) 타입인지 확인할 필요가 있고, 각 필드가 보여주고 문서화할 description을 가진다는 것에서 Form과 Model이 유사한 문법으로 구성된다는 점을 납득할 수 있다. </p> + +<p>Form 데이타는 어플리케이션 디렉토리 안의 forms.py 파일에 저장되어야 한다. <strong>locallibrary/catalog/forms.py</strong> 파일을 생성하고 열어보자. <code>Form</code>을 생성하기 위해, <code>Form</code>클래스에서 파생된, <code>forms</code>라이브러리를 import 하고 폼 필드를 생성한다. 아래는 도서관 책 갱신 폼에 대한 아주 기본적인 폼 클래스이며 이를 생성한 파일에 추가하자.</p> + +<pre class="brush: python">from django import forms + +class RenewBookForm(forms.Form): + renewal_date = forms.DateField(help_text="Enter a date between now and 4 weeks (default 3).") +</pre> + +<h4 id="Form_필드">Form 필드</h4> + +<p>우리가 구현할 구체적인 내용은 다음과 같다. 대여갱신 날짜를 입력할 한 개의 <code><a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#datefield">DateField</a></code> 를 가지는데, 이 필드는 "Renewal date:"라는 라벨로 초기값 없이 빈 칸으로 HTML에 표시되게 된다. 그리고 다음과 같은 도움문구가 추가 된다: "<em>Enter a date between now and 4 weeks (default 3 weeks).</em>" 따로 추가지정할 선택사항 없이, 이 필드는 Django의 <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#django.forms.DateField.input_formats">input_formats</a>: YYYY-MM-DD (2016-11-06), MM/DD/YYYY (02/26/2016), MM/DD/YY (10/25/16) 을 이용하여 날짜를 입력받는다. 그리고 Django의 기본 <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#widget">widget</a>: <a href="https://docs.djangoproject.com/en/2.0/ref/forms/widgets/#django.forms.DateInput">DateInput</a> 를 이용하여 표시될 것이다.</p> + +<p>다음과 같이, 대응되는 모델 필드와 유사성 때문에, 여러분이 의미를 대체로 알만한 수많은 종류의 폼필드가 있다 : <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#booleanfield"><code>BooleanField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#charfield"><code>CharField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#choicefield"><code>ChoiceField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#typedchoicefield"><code>TypedChoiceField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#datefield"><code>DateField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#datetimefield"><code>DateTimeField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#decimalfield"><code>DecimalField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#durationfield"><code>DurationField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#emailfield"><code>EmailField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#filefield"><code>FileField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#filepathfield"><code>FilePathField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#floatfield"><code>FloatField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#imagefield"><code>ImageField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#integerfield"><code>IntegerField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#genericipaddressfield"><code>GenericIPAddressField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#multiplechoicefield"><code>MultipleChoiceField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#typedmultiplechoicefield"><code>TypedMultipleChoiceField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#nullbooleanfield"><code>NullBooleanField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#regexfield"><code>RegexField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#slugfield"><code>SlugField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#timefield"><code>TimeField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#urlfield"><code>URLField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#uuidfield"><code>UUIDField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#combofield"><code>ComboField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#multivaluefield"><code>MultiValueField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#splitdatetimefield"><code>SplitDateTimeField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#modelmultiplechoicefield"><code>ModelMultipleChoiceField</code></a>, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#modelchoicefield"><code>ModelChoiceField</code></a> .</p> + +<p>대부분의 필드에 공통적인 인자들은 아래와 같다. ( 이들은 적절한 기본값을 가지고 있다 ):</p> + +<ul> + <li><a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#required">required</a>: <code>True</code> 로 설정되면, 필드를 빈칸으로 두거나 <code>None</code> 값을 줄 수 없게된다. 보통필드는 required는 True로 기본 설정되므로, 폼에서 빈 칸을 허용하기 위해서는<code>required=False</code> 로 설정해야 한다. </li> + <li><a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#label">label</a>: HTML에서 필드를 렌더링할때 사용하는 레이블이다. <a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#label">label</a> 이 지정되지 않으면, Django는 필드 이름에서 첫번째 문자를 대문자로, 밑줄을 공백으로 변형한 레이블을 새로 생성할 것이다. (예를 들면, renewal_date --> <em>Renewal date</em>).</li> + <li><a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#label-suffix">label_suffix</a>: 기본적으로, 콜론(:)이 레이블 다음에 표시된다. (예를 들면, Renewal date<strong>:</strong>). 이 인자는 다른 문자(들)를 포함한 접미사를 지정할 수 있도록 해준다.</li> + <li><a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#initial">initial</a>: 폼이 나타날 때 해당 필드의 초기 값.</li> + <li><a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#widget">widget</a>: 사용할 디스플레이 위젯.</li> + <li><a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#help-text">help_text</a> (위의 예에서 봤듯이): 필드 사용법을 보여주는 추가적인 문구.</li> + <li><a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#error-messages">error_messages</a>: 해당 필드의 에러 메시지 목록. 필요하면 문구를 수정할 수 있다.</li> + <li><a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#validators">validators</a>: 해당 필드가 유효한 값을 가질 때 호출되는 함수의 목록.</li> + <li><a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#localize">localize</a>: 폼 데이타 입력의 현지화(localisation)를 허용함 (자세한 정보는 해당 링크 참조).</li> + <li><a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/#disabled">disabled</a>: 이 옵션이 <code>True</code> 일때 해당 필드를 볼 수는 있지만 편집이 안됨. 기본 값은 <code>False</code>.</li> +</ul> + +<h4 id="유효성_체크">유효성 체크</h4> + +<p>Django는 데이타의 유효성을 체크할 수 있는 수많은 지점을 제공한다. 어떤 필드의 유효성을 체크하는 가장 쉬운 방법은 해당 필드의 <code>clean_<strong><fieldname></strong>()</code> 메소드를 덮어쓰는 것이다. 예를 들면, 입력된 <code>renewal_date</code> 값이 현재로 부터 4 주이후 사이에 있는지는, <code>clean_<strong>renewal_date</strong>()</code> 를 아래와 같이 구현하여 유효성 체크를 수행할 수 있다.</p> + + + +<p>forms.py 파일을 업데이트 하면 아래와 같은 모습이 된다:</p> + + + +<pre class="brush: python"><code><strong>import datetime</strong> + +from django import forms +<strong>from django.core.exceptions import ValidationError +from django.utils.translation import ugettext_lazy as _ +</strong> +class RenewBookForm(forms.Form): + renewal_date = forms.DateField(help_text="Enter a date between now and 4 weeks (default 3).") + +<strong> def clean_renewal_date(self): + data = self.cleaned_data['renewal_date'] + + # Check if a date is not in the past. + if data < datetime.date.today(): + raise ValidationError(_('Invalid date - renewal in past')) + + # Check if a date is in the allowed range (+4 weeks from today). + if data > datetime.date.today() + datetime.timedelta(weeks=4): + raise ValidationError(_('Invalid date - renewal more than 4 weeks ahead')) + + # Remember to always return the cleaned data. + return data</strong></code></pre> + +<p>주목해야할 지점이 두개 있다. 첫 번째 지점은 <code>self.cleaned_data['renewal_date']</code> 를 이용하여 데이타를 획득하고 이 데이타의 수정여부에 상관없이 함수가 끝나면 이 데이타를 반환한 다는 것이다. 이 단계는 기본 유효성 검사도구를 이용해 입력값을 "다듬고(cleaned)" 잠재적으로 안전하지 않을 수 있는 입력 값을 정화하며 , 해당 입력값에 맞는 표준 형식으로 변환해준다. ( 이 경우에는 Python <code>datetime.datetime</code> 객체 형식이다.).</p> + +<p>두 번째 지점은 입력값이 지정한 범위를 벗어날 경우 <code>ValidationError</code> 에러를 발생시키고, 유효하지 않은 입력값일 때 폼에 보여주고자 하는 에러 문구를 지정하는 부분이다. 위의 예에서는, <a href="https://docs.djangoproject.com/en/2.0/topics/i18n/translation/">Django의 번역 함수들</a> 중하나인 <code>ugettext_lazy()</code> (<code>_()</code> 로 import 됨)로 이 문구를 감싸고 있는데, 당신의 사이트를 나중에 번역하고자 한다면 좋은 예제가 된다.</p> + +<div class="note"> +<p><strong>참고사항:</strong> <a href="https://docs.djangoproject.com/en/2.0/ref/forms/validation/">폼과 필드 유효성 체크</a> (장고 문서임) 에 폼의 유효성 체크에 대한 수많은 다른메소드및 예제가 있다. 예를 들면, 서로 의존관계에 있는 여러개의 필드가 있을 경우, <a href="https://docs.djangoproject.com/en/2.0/ref/forms/api/#django.forms.Form.clean">Form.clean()</a> 함수를 덮어써서, <code>ValidationError</code> 를 다시 발생시킬수도 있다.</p> +</div> + +<p>여기까지가 본 예제에서 필요한 폼에 대한 모든 내용이다!</p> + +<h3 id="URL_Configuration_작성하기">URL Configuration 작성하기</h3> + +<p>뷰를 생성하기 전에, 책 대여갱신 페이지를 위해 URL 설정을 추가 하자. 아래 설정코드를 <strong>locallibrary/catalog/urls.py </strong>아랫 부분에 복사하라.</p> + +<pre class="brush: python">urlpatterns += [ + path('book/<uuid:pk>/renew/', views.renew_book_librarian, name='renew-book-librarian'), +]</pre> + +<p>위 URL 설정코드는 <strong>/catalog/book/<em><bookinstance id></em>/renew/</strong> 형식의 URL을 <strong>views.py</strong> 에 있는 <code>renew_book_librarian()</code> 라는 이름의 함수를 호출하고 <code>BookInstance</code> id를 <code>pk</code>라고 이름지은 매개변수로 전송한다. 위 패턴은 <code>pk</code>가 정확히 <code>uuid</code>의 형식일때만 일치한다.</p> + +<div class="note"> +<p><strong>주목할점</strong>: 추출된 URL 데이타 "<code>pk</code>" 는 당신 마음대로 이름을 정할 수 있다. 왜냐하면 view 함수에 대해서는 어떤 조작이라도 가능하기 때문이다. ( 특정 이름을 기대하는 매개변수를 가진 Generic detail view 클래스를 사용하지 않고 있다.) 하지만 <code>pk</code>는 "primary key"의 약자으로 합리적인 관례상 이름이다 !</p> +</div> + +<h3 id="View_작성하기">View 작성하기</h3> + +<p>위의 <a href="#django_form_handling_process">Django 폼 처리 과정</a> 에서 설명된대로, 위의 폼 뷰는 첫번째로 호출될 때는 기본 폼을 표시해야 한다. 그리고 나서 데이터가 유효하지 않은 경우 에러 메시지를 재 표시하고, 데이터가 유효한 경우에는 데이타를 처리하고 새로운 페이지를 표시해야 한다. 이런 서로 다른 동작을 수행하기 위해, 해당 뷰가 기본 폼을 표시하도록 현재 첫번째로 호출되고 있는지, 데이터 유효성을 체크하기 위해 연속되어 이어지는 호출인지 알 수 있어야 한다. </p> + +<p>서버에 정보를 제출하는 <code>POST</code>리퀘스트를 사용하는 폼에 대해서, 가장 흔한 패턴은 뷰에서 <code>POST</code> 요청 타입 인지 판단 (<code>if request.method == 'POST':</code>) 하여 유효한 요청 여부를 확인하고 <code>GET</code> ( <code>else</code> 조건으로 ) 요청 타입인 경우 초기 폼 생성을 요청한다. <code>GET</code>요청으로 데이터를 제출하려고 한다면 첫 번째 뷰 호출인지 두 번째 이상의 뷰 호출인지 판단하는 전형적인 접근 방법은 폼 데이터를 읽어보는 (즉 폼에서 숨겨진 값을 읽는)것이다.</p> + +<p>책 대여갱신 과정은 데이터베이스에 결과를 보내기 때문에, 관례상 <code>POST</code>요청 방법을 사용한다. 아래 코드는 이런 종류의 function 뷰에 대해 가장 기본적인 형식을 보여준다.</p> + +<pre class="brush: python">import datetime + +from django.shortcuts import get_object_or_404 +from django.http import HttpResponseRedirect +from django.urls import reverse + +from catalog.forms import RenewBookForm + +def renew_book_librarian(request, pk): + book_instance = get_object_or_404(BookInstance, pk=pk) + + # POST 요청이면 폼 데이터를 처리한다 +<strong> if request.method == 'POST':</strong> + + # 폼 인스턴스를 생성하고 요청에 의한 데이타로 채운다 (binding): + book_renewal_form = RenewBookForm(request.POST) + + # 폼이 유효한지 체크한다: + <strong>if book_renewal_form.is_valid():</strong> + # form.cleaned_data 데이타를 요청받은대로 처리한다(여기선 그냥 모델 due_back 필드에 써넣는다) + book_instance.due_back = book_renewal_form.cleaned_data['renewal_date'] + book_instance.save() + + # 새로운 URL로 보낸다: + return HttpResponseRedirect(reverse('all-borrowed') ) + + # GET 요청 (혹은 다른 메소드)이면 기본 폼을 생성한다. +<strong> else:</strong> + proposed_renewal_date = datetime.date.today() + datetime.timedelta(weeks=3) + book_renewal_form = RenewBookForm(initial={'renewal_date': proposed_renewal_date}) + + context = { + 'form': book_renewal_form, + 'book_instance': book_instance, + } + + return render(request, 'catalog/book_renew_librarian.html', context)</pre> + +<p>첫부분에서는 미리 작성된 폼 (<code>RenewBookForm</code>)을 import 하고 뷰 함수의 내부에서 쓰일 유용한 객체나 메소드를 import 한다:</p> + +<ul> + <li><code><a href="https://docs.djangoproject.com/en/2.0/topics/http/shortcuts/#get-object-or-404">get_object_or_404()</a></code>: 해당 모델의 기본 키(primary key) 값에 연결되는 특정 객체를 반환하거나 해당 record가 없을경우 <code>Http404</code>예외를 발생시킨다. </li> + <li><code><a href="https://docs.djangoproject.com/en/2.0/ref/request-response/#django.http.HttpResponseRedirect">HttpResponseRedirect</a></code>: 특정 URL로의 재전송을 생성한다. (HTTP status code 302). </li> + <li><code><a href="https://docs.djangoproject.com/en/2.0/ref/urlresolvers/#django.urls.reverse">reverse()</a></code>: URL 설정(configuration) 의 이름과 전달인자들로 부터 URL을 만들어낸다. 템플릿에서 사용했던 <code>url</code>태그에 해당하는 파이썬 형식의 동일 표현이다.</li> + <li><code><a href="https://docs.python.org/3/library/datetime.html">datetime</a></code>: 날짜와 시간을 다루는 파이썬 라이브러리 이다. </li> +</ul> + +<p>뷰 코드는 첫번째로 현재 <code>BookInstance</code>를 얻기위해 <code>get_object_or_404()</code>함수에 <code>pk</code> 전달인자를 사용한다( <code>BookInstance</code>가 없으면 뷰는 그 즉시 완료되며 페이지에는 "발견 하지 못함" 에러가 뜨게된다). <code>POST</code>요청이아니라면 ( <code>else</code>절로 처리되어) <code>renewal_date</code>필드에 대해 <code>initial</code>값을 넘겨주는 기본 폼을 생성한다. ( 기본 값은 아래 코드에서 볼드체로 표시된대로, 현재 날짜로 부터 3주후이다). </p> + +<pre class="brush: python"> book_instance = get_object_or_404(BookInstance, pk=pk) + + # GET 요청(혹은 다른 메소드)이면 기본 폼을 생성한다. + <strong>else:</strong> + proposed_renewal_date = datetime.date.today() + datetime.timedelta(<strong>weeks=3</strong>) + <strong>book_renewal_form = RenewBookForm(initial={'</strong>renewal_date<strong>': </strong>proposed_renewal_date<strong>})</strong> + + context = { + 'form': book_renewal_form, + 'book_instance': book_instance, + } + + return render(request, 'catalog/book_renew_librarian.html', context)</pre> + +<p>폼을 생성한이후, HTML 페이지를 생성하기 위해 <code>render()</code>를 호출하는데, 이 함수에서 템플릿과 폼을 포함하는 context를 특정한다. 이 경우에 context는 <code>BookInstance</code> 또한 포함하는데, <code>BookInstance</code>는 갱신하고자 하는 책의 정보를 템플릿에 제공하는데 사용한다.</p> + +<p>하지만 <code>POST</code>요청이라면, <code>form</code>객체를 생성하고 <code>POST</code>요청에서의 데이터로 <code>form</code>을 채운다. 이 처리과정은 "binding"으로 불리며 폼의 유효성 체크를 할수 있도록 해준다. 여기에서 모든 필드에 관련된 유효성 체크 코드 - 날짜필드가 실제상황에서 유효한 값을 가지는지 체크하는 일반적인 코드와 날짜가 정해진 범위의 값을 가지는지 체크하는 폼의 특별한 함수인 <code>clean_renewal_date()</code> 를 포함하는 코드 - 를 실행하며 폼의 데이타가 유효한지 체크한다. </p> + +<pre class="brush: python"> book_instance = get_object_or_404(BookInstance, pk=pk) + + # POST 요청이면 폼 데이터를 처리한다 + if request.method == 'POST': + + # 폼 인스턴스를 생성하고 요청에 의한 데이타로 채운다 (binding): +<strong> book_renewal_form = RenewBookForm(request.POST)</strong> + + # 폼이 유효한지 체크한다: + if book_renewal_form.is_valid(): + # form.cleaned_data 데이타를 요청받은대로 처리한다(여기선 그냥 모델 due_back 필드에 써넣는다) + book_inst.due_back = form.cleaned_data['renewal_date'] + book_inst.save() + + # 새로운 URL로 보낸다: + return HttpResponseRedirect(reverse('all-borrowed') ) + + context = { + 'form': book_renewal_form, + 'book_instance': book_instance, + } + + return render(request, 'catalog/book_renew_librarian.html', context)</pre> + +<p>폼의 데이터가 유효하지 않다면 <code>render()</code>함수가 다시 호출된다. 하지만 이번에 context로 넘겨지는 폼의 값에는 에러메시지가 포함될 것이다. </p> + +<p>폼의 데이터가 유효하다면, <code>form.cleaned_data</code>속성을 통해 데이타 사용을 시작할수 있다(즉, 다음과 같다. <code>data = form.cleaned_data['renewal_date']</code>). 여기에서는 단지 폼 데이터를 <code>BookInstance</code>객체에 관련된 <code>due_back</code>변수에 저장했다. </p> + +<div class="warning"> +<p><strong>중요사항</strong>: 'request'객체를 통해 직접 폼 데이터를 가져올수는 있으나 ( 예를 들면 <code>request.POST['renewal_date']</code>나 GET 요청인경우 <code>request.GET['renewal_date']</code>처럼), 이 방식은 <strong>절대</strong> 추천하지 않는다. 위 코드에서 깔끔한 데이타(cleaned_data)란 것은 정제되고(sanitised), 유효성체크가되고, 파이썬에서 많이쓰는 타입의 데이타이다.</p> +</div> + +<p>뷰에서 폼 처리의 마지막 단계는 , 대개는 "Success" 페이지라는 다른 페이지로 주소를 바꾸는 것이다. 여기서는 <code>'all-borrowed'</code>라는 뷰( 이 뷰는 <a href="/en-US/docs/Learn/Server-side/Django/authentication_and_sessions#Challenge_yourself">Django 튜토리얼 파트 8: 사용자 인증과 사용권한</a> 파트에서 "도전과제로" 생성했었다) 로 주소를 바꾸기 위해 <code>HttpResponseRedirect</code>와 <code>reverse()</code>를 사용한다. 당신이 이 페이지를 생성하지 않았다면 URL 주소가 '/'인 홈페이지로 주소를 변경하는 것을 고려해보자.</p> + +<p>여기까지가 폼을 다루기 위해 필요한 모든 것이지만, 해당 폼 뷰의 사용권한을 도서관사서로 한정해야 하는 문제가 남아있다. <code>BookInstance</code>모델에 "<code>can_renew</code>"라는 새로운 사용권한을 추가해야 하겠지만, 작업을 간단하게 하기위해 그냥 기존의 사용권한<code>can_mark_returned</code>에 함수 데코레이터<code>@permission_required</code>를 사용하도록 하겠다.</p> + +<p>그러므로 최종 뷰의 코드는 다음과 같다. 이 코드를 <strong>locallibrary/catalog/views.py</strong> 의 아랫부분에 복사해넣어라.</p> + +<pre class="brush: python">import datetime + +<strong>from django.contrib.auth.decorators import permission_required</strong> +from django.shortcuts import get_object_or_404 +from django.http import HttpResponseRedirect +from django.urls import reverse + +from catalog.forms import RenewBookForm + +<strong>@permission_required('catalog.<code>can_mark_returned</code>')</strong> +def renew_book_librarian(request, pk): + """도서관 사서에 의해 특정 BookInstance를 갱신하는 뷰 함수.""" + book_instance = get_object_or_404(BookInstance, pk=pk) + + # POST 요청이면 폼 데이터를 처리한다 + if request.method == 'POST': + + # 폼 인스턴스를 생성하고 요청에 의한 데이타로 채운다 (binding): + book_renewal_form = RenewBookForm(request.POST) + + # 폼이 유효한지 체크한다: + if book_renewal_form.is_valid(): + # book_renewal_form.cleaned_data 데이타를 요청받은대로 처리한다(여기선 그냥 모델 due_back 필드에 써넣는다) + book_inst.due_back = book_renewal_form.cleaned_data['renewal_date'] + book_inst.save() + + # 새로운 URL로 보낸다: + return HttpResponseRedirect(reverse('all-borrowed') ) + + # GET 요청(혹은 다른 메소드)이면 기본 폼을 생성한다. + else: + proposed_renewal_date = datetime.date.today() + datetime.timedelta(weeks=3) + book_renewal_form = RenewBookForm(initial={'renewal_date': proposed_renewal_date}) + + context = { + 'form': book_renewal_form, + 'book_instance': book_instance, + } + + return render(request, 'catalog/book_renew_librarian.html', context) +</pre> + +<h3 id="Template_작성하기">Template 작성하기</h3> + +<p>뷰 에서 참조되는 템플릿 (<strong>/catalog/templates/catalog/book_renew_librarian.html</strong>)을 생성하고 아래 코드를 복사해넣어라 :</p> + +<pre class="brush: html">{% extends "base_generic.html" %} + +{% block content %} + <h1>Renew: \{{ book_instance.book.title }}</h1> + <p>Borrower: \{{ book_instance.borrower }}</p> + <p{% if book_instance.is_overdue %} class="text-danger"{% endif %}>Due date: \{{book_instance.due_back}}</p> + +<strong> <form action="" method="post"> + {% csrf_token %} + \{{ form.as_table }} + <input type="submit" value="Submit"> + </form></strong> +{% endblock %}</pre> + +<p>이 작업의 대부분은 앞선 튜토리얼에서 익숙해진 작업이다. 우리는 베이스 템플릿을 확장하고 콘텐츠 블럭을 재설정한다. <code>\{{bookinst}}</code>(와 그에 따른 변수) 가 <code>render()</code> 함수 내의 컨텍스트 객체로 넘겨졌기 때문에 <code>\{{bookinst}}</code>를 참조할수 있다. 이들을 이용해 책 제목, 대여자 그리고 이전 대여마감일의 목록을 열거한다.</p> + +<p>폼 코드는 상대적으로 간단하다. 우선 form이 어디에 제출될 것인지(<code>action</code>)(POST인지 PUT인지) 명시하여 <code>form</code> 태그를 선언하고, 데이터를 제출하는 <code>method</code> 를 명시한다(이 경우에는 "HTTP POST") — 해당 페이지 위 쪽의 <a href="#HTML_forms">HTML Forms</a> overview에서 보았듯이, <code>action</code>을 비워 놓았는데, 이렇게 하면 form 데이터가 현재 URL페이지로 다시 POST 된다(지금 우리가 하고자 하는 것입니다!). <code>form</code> 태그 안에는 <code>submit</code> input 태그 또한 만들어서 페이지 사용자가 눌러서 데이터를 제출(submit)할 수 있도록 한다. <code>form</code> 태그 안에정의된 또 다른 하나인 <code>{% csrf_token %}</code>는 Django의 cross-site 위조 방지의 방식 중 하나이다. </p> + +<div class="note"> +<p><strong>Note:</strong> Add the <code>{% csrf_token %}</code> to every Django template you create that uses <code>POST</code> to submit data. This will reduce the chance of forms being hijacked by malicious users.</p> +</div> + +<p>마지막으로 템플릿에 context라는 dictionary형 데이터로 넘기는 <code>\{{form}}</code> 변수가 남았다. 별로 놀랍지 않을 수 있지만, 아래처럼 하면 form의 모든 field의 필드, 위젯, 도움말을 함께 렌더링하는 기본 렌더링기능을 사용할 수 있다 — 렌더링된 결과는 다음과 같다.</p> + +<pre class="brush: html"><tr> + <t><label for="id_renewal_date">Renewal date:</label></th> + <td> + <input id="id_renewal_date" name="renewal_date" type="text" value="2016-11-08" required /> + <br /> + <span class="helptext">Enter date between now and 4 weeks (default 3 weeks).</span> + </td> +</tr> +</pre> + +<div class="note"> +<p><strong>Note:</strong> 필드가 하나만 있기 때문에 분명하지는 않지만 기본적으로 모든 필드는 자체 테이블 행에 정의되어 있습니다. 템플릿 변수 <code>\{{ form.as_table }}</code>을 참조하면이 동일한 렌더링이 제공됩니다. </p> +</div> + +<p>유효하지 않은 날짜를 입력하는 경우 페이지에서 렌더링 된 오류 목록 (아래 굵게 표시)을 얻게됩니다.</p> + +<pre class="brush: html"><tr> + <th><label for="id_renewal_date">Renewal date:</label></th> + <td> +<strong> <ul class="errorlist"> + <li>Invalid date - renewal in past</li> + </ul></strong> + <input id="id_renewal_date" name="renewal_date" type="text" value="2015-11-08" required /> + <br /> + <span class="helptext">Enter date between now and 4 weeks (default 3 weeks).</span> + </td> +</tr></pre> + +<h4 id="Form_template_variable을_사용하는_다른_방법">Form template variable을 사용하는 다른 방법</h4> + +<p>위와 같이 <code>\{{form.as_table</code><code>}}</code> 을 사용하면 각 필드가 테이블 행으로 렌더링됩니다. 또한 각 필드를 <code>\{{form.as_ul}}</code> 을 사용하여 목록항목(list item)으로 렌더링하거나 <code>\{{form.as_p}}</code>를 사용하여 단락(paragraph)으로 렌더링 할 수도 있습니다.</p> + +<p>또한 dot notation을 사용하여 form 속성을 인덱싱하여 각 부분 렌더링을 완벽하게 제어 할 수도 있습니다. 예를 들어, <code>renewal_date</code> 필드에 대한 여러 개의 개별 항목에 접근 할 수 있습니다.</p> + +<ul> + <li><code>\{{form.renewal_date}}:</code> The whole field.</li> + <li><code>\{{form.renewal_date.errors}}</code>: The list of errors.</li> + <li><code>\{{form.renewal_date.id_for_label}}</code>: The id of the label.</li> + <li><code>\{{form.renewal_date.help_text}}</code>: The field help text.</li> +</ul> + +<p>템플릿의 양식을 수동으로 렌더링하고 템플릿 필드를 동적으로 반복하는 방법에 대한 자세한 예제는, <a href="https://docs.djangoproject.com/en/2.0/topics/forms/#rendering-fields-manually">Working with forms > Rendering fields manually</a> (Django docs)를 참고.</p> + +<h3 id="Page를_시험하기">Page를 시험하기</h3> + +<p>If you accepted the "challenge" in <a href="/en-US/docs/Learn/Server-side/Django/authentication_and_sessions#Challenge_yourself">Django Tutorial Part 8: User authentication and permissions</a> you'll have a list of all books on loan in the library, which is only visible to library staff. We can add a link to our renew page next to each item using the template code below.</p> + +<pre class="brush: html">{% if perms.catalog.can_mark_returned %}- <a href="{% url 'renew-book-librarian' bookinst.id %}">Renew</a> {% endif %}</pre> + +<div class="note"> +<p><strong>Note</strong>: Remember that your test login will need to have the permission "<code>catalog.can_mark_returned</code>" in order to access the renew book page (perhaps use your superuser account).</p> +</div> + +<p>You can alternatively manually construct a test URL like this — <a href="http://127.0.0.1:8000/catalog/book/<bookinstance id>/renew/">http://127.0.0.1:8000/catalog/book/<em><bookinstance_id></em>/renew/</a> (a valid bookinstance id can be obtained by navigating to a book detail page in your library, and copying the <code>id</code> field).</p> + +<h3 id="What_does_it_look_like">What does it look like?</h3> + +<p>If you are successful, the default form will look like this:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14209/forms_example_renew_default.png" style="border-style: solid; border-width: 1px; display: block; height: 292px; margin: 0px auto; width: 680px;"></p> + +<p>The form with an invalid value entered, will look like this:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14211/forms_example_renew_invalid.png" style="border-style: solid; border-width: 1px; display: block; height: 290px; margin: 0px auto; width: 658px;"></p> + +<p>The list of all books with renew links will look like this:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14207/forms_example_renew_allbooks.png" style="border-style: solid; border-width: 1px; display: block; height: 256px; margin: 0px auto; width: 613px;"></p> + +<h2 id="ModelForms">ModelForms</h2> + +<p>Creating a <code>Form</code> class using the approach described above is very flexible, allowing you to create whatever sort of form page you like and associate it with any model or models.</p> + +<p>However if you just need a form to map the fields of a <em>single</em> model then your model will already define most of the information that you need in your form: fields, labels, help text, etc. Rather than recreating the model definitions in your form, it is easier to use the <a href="https://docs.djangoproject.com/en/2.0/topics/forms/modelforms/">ModelForm</a> helper class to create the form from your model. This <code>ModelForm</code> can then be used within your views in exactly the same way as an ordinary <code>Form</code>.</p> + +<p>A basic <code>ModelForm</code> containing the same field as our original <code>RenewBookForm</code> is shown below. All you need to do to create the form is add <code>class Meta</code> with the associated <code>model</code> (<code>BookInstance</code>) and a list of the model <code>fields</code> to include in the form (you can include all fields using <code>fields = '__all__'</code>, or you can use <code>exclude</code> (instead of <code>fields</code>) to specify the fields <em>not </em>to include from the model).</p> + +<pre class="brush: python">from django.forms import ModelForm +from .models import BookInstance + +class RenewBookModelForm(ModelForm): +<strong> class Meta: + model = BookInstance + fields = ['due_back',]</strong> +</pre> + +<div class="note"> +<p><strong>Note</strong>: This might not look like all that much simpler than just using a <code>Form</code> (and it isn't in this case, because we just have one field). However if you have a lot of fields, it can reduce the amount of code quite significantly!</p> +</div> + +<p>The rest of the information comes from the model field definitions (e.g. labels, widgets, help text, error messages). If these aren't quite right, then we can override them in our <code>class Meta</code>, specifying a dictionary containing the field to change and its new value. For example, in this form we might want a label for our field of "<em>Renewal date</em>" (rather than the default based on the field name: <em>Due date</em>), and we also want our help text to be specific to this use case. The <code>Meta</code> below shows you how to override these fields, and you can similarly set <code>widgets</code> and <code>error_messages</code> if the defaults aren't sufficient.</p> + +<pre class="brush: python">class Meta: + model = BookInstance + fields = ['due_back',] +<strong> labels = { 'due_back': _('Renewal date'), } + help_texts = { 'due_back': _('Enter a date between now and 4 weeks (default 3).'), } </strong> +</pre> + +<p>To add validation you can use the same approach as for a normal <code>Form</code> — you define a function named <code>clean_<em>field_name</em>()</code> and raise <code>ValidationError</code> exceptions for invalid values. The only difference with respect to our original form is that the model field is named <code>due_back</code> and not "<code>renewal_date</code>".</p> + +<pre class="brush: python">from django.forms import ModelForm +from .models import BookInstance + +class RenewBookModelForm(ModelForm): +<strong> def clean_due_back(self): + data = self.cleaned_data['due_back'] + + #Check date is not in past. + if data < datetime.date.today(): + raise ValidationError(_('Invalid date - renewal in past')) + + #Check date is in range librarian allowed to change (+4 weeks) + if data > datetime.date.today() + datetime.timedelta(weeks=4): + raise ValidationError(_('Invalid date - renewal more than 4 weeks ahead')) + + # Remember to always return the cleaned data. + return data +</strong> + class Meta: + model = BookInstance + fields = ['due_back',] + labels = { 'due_back': _('Renewal date'), } + help_texts = { 'due_back': _('Enter a date between now and 4 weeks (default 3).'), } +</pre> + +<p>The class <code>RenewBookModelForm</code> below is now functionally equivalent to our original <code>RenewBookForm</code>. You could import and use it wherever you currently use <code>RenewBookForm</code>.</p> + +<h2 id="Generic_editing_views">Generic editing views</h2> + +<p>The form handling algorithm we used in our function view example above represents an extremely common pattern in form editing views. Django abstracts much of this "boilerplate" for you, by creating <a href="https://docs.djangoproject.com/en/2.0/ref/class-based-views/generic-editing/">generic editing views</a> for creating, editing, and deleting views based on models. Not only do these handle the "view" behaviour, but they automatically create the form class (a <code>ModelForm</code>) for you from the model.</p> + +<div class="note"> +<p><strong>Note: </strong>In addition to the editing views described here, there is also a <a href="https://docs.djangoproject.com/en/2.0/ref/class-based-views/generic-editing/#formview">FormView</a> class, which lies somewhere between our function view and the other generic views in terms of "flexibility" vs "coding effort". Using <code>FormView</code> you still need to create your <code>Form</code>, but you don't have to implement all of the standard form-handling pattern. Instead you just have to provide an implementation of the function that will be called once the submitted is known to be be valid.</p> +</div> + +<p>In this section we're going to use generic editing views to create pages to add functionality to create, edit, and delete <code>Author</code> records from our library — effectively providing a basic reimplementation of parts of the Admin site (this could be useful if you need to offer admin functionality in a more flexible way that can be provided by the admin site).</p> + +<h3 id="Views">Views</h3> + +<p>Open the views file (<strong>locallibrary/catalog/views.py</strong>) and append the following code block to the bottom of it:</p> + +<pre class="brush: python">from django.views.generic.edit import CreateView, UpdateView, DeleteView +from django.urls import reverse_lazy +from .models import Author + +class AuthorCreate(CreateView): + model = Author + fields = '__all__' + initial={'date_of_death':'05/01/2018',} + +class AuthorUpdate(UpdateView): + model = Author + fields = ['first_name','last_name','date_of_birth','date_of_death'] + +class AuthorDelete(DeleteView): + model = Author + success_url = reverse_lazy('authors')</pre> + +<p>As you can see, to create the views you need to derive from <code>CreateView</code>, <code>UpdateView</code>, and <code>DeleteView</code> (respectively) and then define the associated model.</p> + +<p>For the "create" and "update" cases you also need to specify the fields to display in the form (using in same syntax as for <code>ModelForm</code>). In this case we show both the syntax to display "all" fields, and how you can list them individually. You can also specify initial values for each of the fields using a dictionary of <em>field_name</em>/<em>value</em> pairs (here we arbitrarily set the date of death for demonstration purposes — you might want to remove that!). By default these views will redirect on success to a page displaying the newly created/edited model item, which in our case will be the author detail view we created in a previous tutorial. You can specify an alternative redirect location by explicitly declaring parameter <code>success_url</code> (as done for the <code>AuthorDelete</code> class).</p> + +<p>The <code>AuthorDelete</code> class doesn't need to display any of the fields, so these don't need to be specified. You do however need to specify the <code>success_url</code>, because there is no obvious default value for Django to use. In this case we use the <code><a href="https://docs.djangoproject.com/en/2.0/ref/urlresolvers/#reverse-lazy">reverse_lazy()</a></code> function to redirect to our author list after an author has been deleted — <code>reverse_lazy()</code> is a lazily executed version of <code>reverse()</code>, used here because we're providing a URL to a class-based view attribute.</p> + +<h3 id="Templates">Templates</h3> + +<p>The "create" and "update" views use the same template by default, which will be named after your model: <em>model_name</em><strong>_form.html</strong> (you can change the suffix to something other than <strong>_form</strong> using the <code>template_name_suffix</code> field in your view, e.g. <code>template_name_suffix = '_other_suffix'</code>)</p> + +<p>Create the template file <strong>locallibrary/catalog/templates/catalog/author_form.html</strong> and copy in the text below.</p> + +<pre class="brush: html">{% extends "base_generic.html" %} + +{% block content %} + +<form action="" method="post"> + {% csrf_token %} + <table> + \{{ form.as_table }} + </table> + <input type="submit" value="Submit" /> + +</form> +{% endblock %}</pre> + +<p>This is similar to our previous forms, and renders the fields using a table. Note also how again we declare the <code>{% csrf_token %}</code> to ensure that our forms are resistant to CSRF attacks.</p> + +<p>The "delete" view expects to find a template named with the format <em>model_name</em><strong>_confirm_delete.html</strong> (again, you can change the suffix using <code>template_name_suffix</code> in your view). Create the template file <strong>locallibrary/catalog/templates/catalog/author_confirm_delete</strong><strong>.html</strong> and copy in the text below.</p> + +<pre class="brush: html">{% extends "base_generic.html" %} + +{% block content %} + +<h1>Delete Author</h1> + +<p>Are you sure you want to delete the author: \{{ author }}?</p> + +<form action="" method="POST"> + {% csrf_token %} + <input type="submit" action="" value="Yes, delete." /> +</form> + +{% endblock %} +</pre> + +<h3 id="URL_configurations">URL configurations</h3> + +<p>Open your URL configuration file (<strong>locallibrary/catalog/urls.py</strong>) and add the following configuration to the bottom of the file:</p> + +<pre class="brush: python">urlpatterns += [ + path('author/create/', views.AuthorCreate.as_view(), name='author_create'), + path('author/<int:pk>/update/', views.AuthorUpdate.as_view(), name='author_update'), + path('author/<int:pk>/delete/', views.AuthorDelete.as_view(), name='author_delete'), +]</pre> + +<p>There is nothing particularly new here! You can see that the views are classes, and must hence be called via <code>.as_view()</code>, and you should be able to recognise the URL patterns in each case. We must use <code>pk</code> as the name for our captured primary key value, as this is the parameter name expected by the view classes.</p> + +<p>The author create, update, and delete pages are now ready to test (we won't bother hooking them into the site sidebar in this case, although you can do so if you wish).</p> + +<div class="note"> +<p><strong>Note</strong>: Observant users will have noticed that we didn't do anything to prevent unauthorised users from accessing the pages! We leave that as an exercise for you (hint: you could use the <code>PermissionRequiredMixin</code> and either create a new permission or reuse our <code>can_mark_returned</code> permission).</p> +</div> + +<h3 id="Testing_the_page">Testing the page</h3> + +<p>First login to the site with an account that has whatever permissions you decided are needed to access the author editing pages.</p> + +<p>Then navigate to the author create page: <a href="http://127.0.0.1:8000/catalog/author/create/">http://127.0.0.1:8000/catalog/author/create/</a>, which should look like the screenshot below.</p> + +<p><img alt="Form Example: Create Author" src="https://mdn.mozillademos.org/files/14223/forms_example_create_author.png" style="border-style: solid; border-width: 1px; display: block; height: 184px; margin: 0px auto; width: 645px;"></p> + +<p>Enter values for the fields and then press <strong>Submit</strong> to save the author record. You should now be taken to a detail view for your new author, with a URL of something like <em>http://127.0.0.1:8000/catalog/author/10</em>.</p> + +<p>You can test editing records by appending <em>/update/</em> to the end of the detail view URL (e.g. <em>http://127.0.0.1:8000/catalog/author/10/update/</em>) — we don't show a screenshot, because it looks just like the "create" page!</p> + +<p>Last of all we can delete the page, by appending delete to the end of the author detail-view URL (e.g. <em>http://127.0.0.1:8000/catalog/author/10/delete/</em>). Django should display the delete page shown below. Press <strong>Yes, delete.</strong> to remove the record and be taken to the list of all authors.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14221/forms_example_delete_author.png" style="border-style: solid; border-width: 1px; display: block; height: 194px; margin: 0px auto; width: 561px;"></p> + + + +<h2 id="Challenge_yourself">Challenge yourself</h2> + +<p>Create some forms to create, edit and delete <code>Book</code> records. You can use exactly the same structure as for <code>Authors</code>. If your <strong>book_form.html</strong> template is just a copy-renamed version of the <strong>author_form.html</strong> template, then the new "create book" page will look like the screenshot below:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14225/forms_example_create_book.png" style="border-style: solid; border-width: 1px; display: block; height: 521px; margin: 0px auto; width: 595px;"></p> + +<ul> +</ul> + +<h2 id="Summary">Summary</h2> + +<p>Creating and handling forms can be a complicated process! Django makes it much easier by providing programmatic mechanisms to declare, render and validate forms. Furthermore, Django provides generic form editing views that can do <em>almost all</em> the work to define pages that can create, edit, and delete records associated with a single model instance.</p> + +<p>There is a lot more that can be done with forms (check out our See also list below), but you should now understand how to add basic forms and form-handling code to your own websites.</p> + +<h2 id="See_also">See also</h2> + +<ul> + <li><a href="https://docs.djangoproject.com/en/2.0/topics/forms/">Working with forms</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.0/intro/tutorial04/#write-a-simple-form">Writing your first Django app, part 4 > Writing a simple form</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.0/ref/forms/api/">The Forms API</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.0/ref/forms/fields/">Form fields</a> (Django docs) </li> + <li><a href="https://docs.djangoproject.com/en/2.0/ref/forms/validation/">Form and field validation</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.0/topics/class-based-views/generic-editing/">Form handling with class-based views</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.0/topics/forms/modelforms/">Creating forms from models</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.0/ref/class-based-views/generic-editing/">Generic editing views</a> (Django docs)</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Django/authentication_and_sessions", "Learn/Server-side/Django/Testing", "Learn/Server-side/Django")}}</p> + + + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Server-side/Django/Introduction">Django introduction</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/development_environment">Setting up a Django development environment</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Django Tutorial: The Local Library website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django Tutorial Part 2: Creating a skeleton website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Models">Django Tutorial Part 3: Using models</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Admin_site">Django Tutorial Part 4: Django admin site</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django Tutorial Part 5: Creating our home page</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Generic_views">Django Tutorial Part 6: Generic list and detail views</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Sessions">Django Tutorial Part 7: Sessions framework</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Authentication">Django Tutorial Part 8: User authentication and permissions</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Forms">Django Tutorial Part 9: Working with forms</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Testing">Django Tutorial Part 10: Testing a Django web application</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Django Tutorial Part 11: Deploying Django to production</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/web_application_security">Django web application security</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></li> +</ul> diff --git a/files/ko/learn/server-side/django/generic_views/index.html b/files/ko/learn/server-side/django/generic_views/index.html new file mode 100644 index 0000000000..f3f496f97c --- /dev/null +++ b/files/ko/learn/server-side/django/generic_views/index.html @@ -0,0 +1,623 @@ +--- +title: 'Django Tutorial Part 6: Generic list and detail views' +slug: Learn/Server-side/Django/Generic_views +translation_of: Learn/Server-side/Django/Generic_views +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Django/Home_page", "Learn/Server-side/Django/Sessions", "Learn/Server-side/Django")}}</div> + +<p class="summary">이 튜토리얼은 <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a> website에 책과 저자의 목록과 세부 페이지를 추가 하여 확장할 것입니다. 이 글에서 우리는 제네릭 클래스-기반 뷰(generic class-based views)에 대해 배울 것이며, 그것이 일반적인 사용 사례를 위해 작성해야 하는 코드들을 줄이는 방법을 보여줄 것입니다. 우리는 또한 URL 처리에 대해 더 세부적으로 알아볼 것이며, 기본 패턴 매칭(basic pattern matching)을 수행하는 방법을 보여줄 것입니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">사전 준비:</th> + <td><a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django Tutorial Part 5: Creating our home page</a>를 포함한 모든 이전 튜토리얼을 완료하세요.</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>제네릭 클래스-기반 뷰를 어디 그리고 어떻게 사용하는지, 그리고 어떻게 URL들로부터 패턴들을 추출하여 정보를 view들에게 전달하는지에 대해 이해하기.</td> + </tr> + </tbody> +</table> + +<h2 id="개요">개요</h2> + +<p>이 튜토리얼에서 우리는 책과 저자에 대한 목록과 세부 페이지(detail page)를 추가하여 <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a> 웹사이트의 첫 번째 버전을 완성할 것입니다(더 정확하게는, 우리는 책 페이지들을 구현하는 방법을 보여주고, 저자 페이지는 스스로 완성하도록 할 것입니다!)</p> + +<p>이 과정은 이전 튜토리얼에서 보여준, 색인 페이지(index page)를 만드는 과정과 비슷합니다. 우리는 여전히 URL 맵들, view들, 그리고 탬플릿들을 만들어야 합니다. 주요한 차이점은 세부 페이지(detail pages)에서, 우리는 URL 안의 패턴에서 정보를 추출해서 view로 전달하는 추가적인 도전을 가진다는 점입니다. </p> + +<p>이 튜토리얼의 마지막에서는 제네릭 클래스-기반 뷰를 사용할 때 데이터의 페이지를 매기는 방법을 보여드리겠습니다.</p> + +<h2 id="책_목록_페이지">책 목록 페이지</h2> + +<p>책 목록 페이지는 모든 사용 가능한 책 레코드들의 목록을 페이지 안에 나타낼 것이며, 다음 URL을 사용하여 접근합니다: <code>catalog/books</code>/. 이 페이지는 각 레코드마다 제목과 저자를 나타낼 것이며, 제목은 관련된 책 페이지로 이동하는 하이퍼링크 처리됩니다. 이 페이지는 사이트의 다른 페이지들과 같은 구조와 내비게이션을 가지고 있어서, 우리는 이전 튜토리얼에서 만들었던 템플릿(<strong>base_generic.html</strong>)을 확장해서 사용하면 됩니다.</p> + +<h3 id="URL_mapping">URL mapping</h3> + +<p><strong>/catalog/urls.py </strong>파일을 열고 아래 코드박스의 굵은 글씨를 복사해 붙여넣으세요. 인덱스 페이지처럼 <code>path()</code> 함수는 URL('<strong>books/'</strong>)과 매치되는 패턴, URL이 매치될 때 호출되는 view 함수<code>(views.BookListView.as_view())</code>, 그리고 이 특정 매핑에 대한 이름을 정의합니다.</p> + +<pre class="brush: python">urlpatterns = [ + path('', views.index, name='index'), +<strong> </strong>path<strong>('books/', views.BookListView.as_view(), name='books'),</strong> +]</pre> + +<p>이전 튜토리얼에서 URL은 이미 <code>/catalog</code> 와 매치되었을 것입니다. 그래서 사실상 view는 <code>/catalog/books/</code> URL에 접속하면 호출됩니다.</p> + +<p>View함수는 이전과 다른 형태를 가집니다. 왜냐면 이 view는 사실 클래스로 구현이 되기 때문입니다. 우리는 이 view를 직접 구현하지 않고, 이미 존재하는 generic view 함수를 상속받아 view 함수를 구현할 것입니다. 이 generic view 함수는 우리가 구현하고 싶은 기능들을 거의 다 가지고 있습니다.</p> + +<p>Django의 클래스 기반 view에서는, <code>as_view()</code>클래스 메소드를 호출해 적절한 view 함수에 접근할 수 있습니다. 이건 클래스의 인스턴스를 생성하는 작업과 모든 HTTP 요청을 처리하는 핸들러 메소드가 제대로 동작하는지를 처리합니다.</p> + +<h3 id="뷰(클래스_기반)">뷰(클래스 기반)</h3> + +<p>표준 function으로 우리는 꽤나 쉽게 book list view를 만들 수 있는데 (마치 이전 우리의 index view같이), 모든 책에 대한 데이터 베이스 쿼리를 만들어서 <code>render()</code> 함수를 불러 특정 템플릿에 리스트를 보냅니다. 대신 우리는 class-based generic list view (<code>ListView</code>) 를 사용하는데— 존재하는 뷰로부터 상속받아온 클래스입니다. generic view가 이미 우리가 필요한 대부분의 기능성을 실행하면서 동시에 Django best-practice이기 때문에, 우리는 코드의 양과 반복을 줄이고 궁극적으로 유지보수에 수고가 덜 드는 견고한 리스트 뷰를 만들 수 있습니다.</p> + +<p><strong>catalog/views.py </strong>파일을 열고, 아래의 코드를 views.py 파일 가장 아래에 붙여넣기하세요.</p> + +<pre class="brush: python">from django.views import generic + +class BookListView(generic.ListView): + model = Book</pre> + +<p>이게 전부입니다! Generic view는 명시된 모델(Book)의 모든 레코드를 가져오기 위해 데이터베이스를 쿼리할 것이고, <strong>/locallibrary/catalog/templates/catalog/book_list.html</strong>(아래에서 만들 예정)경로에 있는 템플릿을 렌더링합니다. 템플릿 안에서 우리는 <code>object_list</code>나 <code>book_list</code>라는 템플릿 변수를 사용해 도서 목록에 접근할 수 있습니다. (일반적으로 "<code><em>the_model_name</em>_list</code>").</p> + +<div class="note"> +<p><strong>Note</strong>: 이 어색한 템플릿 경로는 오타가 아닙니다. Generic views는 <code>/<em>application_name</em>/<em>the_model_name</em>_list.html</code>(지금 상황에서는 <code>catalog/book_list.html</code>)에서 템플릿을 찾습니다. 이 경로는 애플리캐이션의 <code>/<em>application_name</em>/templates/</code> 디렉토리 안에 있습니다(<code>/catalog/templates/)</code>.</p> +</div> + +<p>속성이나 디폴트 동작을 추가할 수도 있습니다. 예를 들어, 같은 모델을 사용하지만 여러 개의 뷰를 사용해야 되는 경우 다른 템플릿 파일을 명시할 수 있습니다. 혹은 <code>book_list</code> 템플릿 변수명이 직관적이지 않다고 생각해 다른 템플릿 변수명을 사용하고 싶을지도 모릅니다. 아마 가장 유용한 바리에이션은 리턴 값의 결과를 바꾸거나 필터링하는 것입니다. 따라서 모든 책을 나열하는 대신, 유저가 읽은 순으로 5개의 책을 나열할 수도 있습니다.</p> + +<pre class="brush: python">class BookListView(generic.ListView): + model = Book + context_object_name = 'my_book_list' # your own name for the list as a template variable + queryset = Book.objects.filter(title__icontains='war')[:5] # Get 5 books containing the title war + template_name = 'books/my_arbitrary_template_name_list.html' # Specify your own template name/location</pre> + +<h4 id="클래스_기반_뷰의_메소드_오버라이딩">클래스 기반 뷰의 메소드 오버라이딩</h4> + +<p>굳이 여기서 할 필요는 없지만, 클래스 메소드 오버라이딩을 할 수도 있습니다.</p> + +<p>예를 들어, 우리는 <code>get_queryset()</code>메소드를 오버라이딩해 반환되는 레코드의 리스트들을 바꿀 수 있습니다. 이건 우리가 이전에 했던 <code>queryset</code> 속성을 지정하는 방법보다 더 유연한 방법입니다. (비록 지금 상황에서 별 이득이 되지는 않지만요.)</p> + +<pre class="brush: python">class BookListView(generic.ListView): + model = Book + + def get_queryset(self): + return Book.objects.filter(title__icontains='war')[:5] # Get 5 books containing the title war +</pre> + +<p>우리는 템플릿에 추가적인 컨텍스트 변수들을 전달하기 위해 <code>get_context_data()</code>를 오버라이딩할 수도 있습니다. (도서 목록이 디폴트로 전달됩니다.) 아래의 코드는 <code>some_data</code> 라는 이름의 변수를 어떻게 컨텍스트에 추가하는지를 보여줍니다. (이렇게 하면 템플릿 변수로 사용할 수 있습니다.)</p> + +<pre class="brush: python">class BookListView(generic.ListView): + model = Book + + def get_context_data(self, **kwargs): + # Call the base implementation first to get the context + context = super(BookListView, self).get_context_data(**kwargs) + # Create any data and add it to the context + context['some_data'] = 'This is just some data' + return context</pre> + +<p>이렇게 할 때에는, 아래의 패턴을 따르는 것이 중요합니다:</p> + +<ul> + <li>첫째로, 슈퍼클래스에서 기존 컨텍스트를 가져옵니다.</li> + <li>그리고 새로운 컨텍스트 정보를 추가합니다. </li> + <li>마지막으로 새롭게 업데이트된 컨텍스트를 리턴합니다.</li> +</ul> + +<div class="note"> +<p><strong>Note</strong>: <a href="https://docs.djangoproject.com/en/2.0/topics/class-based-views/generic-display/">Built-in class-based generic views</a> (Django docs)를 방문해 다양한 예제를 살펴볼 수 있습니다.</p> +</div> + +<h3 id="리스트_뷰_템플릿_생성하기">리스트 뷰 템플릿 생성하기</h3> + +<p><strong>/locallibrary/catalog/templates/catalog/book_list.html</strong> 경로에 HTML 파일을 만든 다음, 아래의 코드를 복사, 붙여넣기 하세요. 이전에 설명한 것처럼, 이건 제네릭 클래스 기반 리스트 뷰에서 예상되는 기본 템플릿 파일입니다. (<code>catalog</code> 애플리케이션 내의 <code>Book</code> 모델)</p> + +<p>제네릭 뷰의 템플릿은 다른 템플릿과 비슷합니다 (물론 템플릿에 전달되는 컨텍스트나 정보는 다를지도 모르지만요). 다른 index 템플릿처럼, 우리는 첫번째 줄에 base 템플릿을 넣어 확장한 다음, <code>content</code>라는 이름의 블록으로 교체합니다.</p> + +<pre class="brush: html">{% extends "base_generic.html" %} + +{% block content %} + <h1>Book List</h1> + <strong>{% if book_list %}</strong> + <ul> + {% for book in book_list %} + <li> + <a href="\{{ book.get_absolute_url }}">\{{ book.title }}</a> (\{{book.author}}) + </li> + {% endfor %} + </ul> + <strong>{% else %}</strong> + <p>There are no books in the library.</p> + <strong>{% endif %} </strong> +{% endblock %}</pre> + +<p>뷰는 <code>object_list</code>나 <code>book_list</code>라는 디폴트 aliases로 컨텍스트(도서 목록)를 전달합니다. <code>object_list</code>나 <code>book_list</code> 둘 중 어느 것을 적어도 상관이 없습니다.</p> + +<h4 id="조건부_실행">조건부 실행</h4> + +<p><code><a href="https://docs.djangoproject.com/en/2.0/ref/templates/builtins/#if">if</a></code>, <code>else</code> 그리고 <code>endif</code> 라는 템플릿 태그들은 <code>book_list</code> 이 정의되었는지, 그리고 존재하는지 체크합니다. 만약 <code>book_list</code>가 없다면, 책이 존재하지 않는다는 <code>else</code> 절의 텍스트 문구가 표시될 것입니다. 만약 <code>book_list</code>가 존재한다면, 도서 목록의 갯수만큼 반복만큼 반복해서 실행합니다.</p> + +<pre class="brush: html"><strong>{% if book_list %}</strong> + <!-- code here to list the books --> +<strong>{% else %}</strong> + <p>There are no books in the library.</p> +<strong>{% endif %}</strong> +</pre> + +<p>위의 조건문은 단 하나의 상황만 체크합니다. 하지만 <code>elif</code>라는 템플릿 태그를 사용해 추가적인 조건을 걸어 테스트할 수 있습니다. (예를 들면 <code>{% elif var2 %}</code>) 조건부 연산자에 대한 자세한 내용은 다음 링크에서 확인할 수 있습니다: <a href="https://docs.djangoproject.com/en/2.0/ref/templates/builtins/#if">if</a>, <a href="https://docs.djangoproject.com/en/2.0/ref/templates/builtins/#ifequal-and-ifnotequal">ifequal/ifnotequal</a>, and <a href="https://docs.djangoproject.com/en/2.0/ref/templates/builtins/#ifchanged">ifchanged</a> in <a href="https://docs.djangoproject.com/en/2.0/ref/templates/builtins">Built-in template tags and filters</a> (Django Docs).</p> + +<h4 id="반복_구문">반복 구문</h4> + +<p><a href="https://docs.djangoproject.com/en/2.0/ref/templates/builtins/#for">for</a> 와 <code>endfor</code> 라는 템플릿 태그들은 아래와 같이 도서 목록을 살펴보는 루프를 위해 사용합니다. 각각의 반복은 <code>book</code> 템플릿 변수에 현재 리스트 아이템에 대한 정보를 채웁니다.</p> + +<pre class="brush: html">{% for <strong>book</strong> in book_list %} + <li> <!-- code here get information from each <strong>book</strong> item --> </li> +{% endfor %} +</pre> + +<p>여기에서는 사용되지 않지만, 반복 구문 내에서 Django는 반복을 추적할 수 있는 다른 변수들을 만들 수 있습니다. 예를 들어, <code>forloop.last</code>라는 변수로 루프의 마지막 실행에 대한 조건부 처리을 할 수 있습니다.</p> + +<h4 id="변수_접근하기">변수 접근하기</h4> + +<p>반복 구문 내에서의 코드는 각각의 책에 대한 리스트 아이템을 생성합니다. 이 리스트 아이템은 타이틀(아직 작성되지 않은 상세 뷰의 링크)과 작가의 이름을 나타냅니다.</p> + +<pre class="brush: html"><a href="\{{ book.get_absolute_url }}">\{{ book.title }}</a> (\{{book.author}}) +</pre> + +<p>우리는 점 표기법(dot notation)을 사용해서 연관된 책의 레코드(예를 들어 <code>book.title</code> 과 <code>book.author</code>)에 대한 필드에 접근이 가능합니다. <code>book</code> 다음의 텍스트는 모델에 정의되어있는 필드의 이름입니다.</p> + +<p>우리는 템플릿 안에 모델에서 정의한 함수를 불러올 수도 있습니다. 이 경우, 우리는 <code>Book.get_absolute_url()</code> 함수를 호출해 연관된 세부 레코드를 표시하는 URL을 가져옵니다. 이 작업은 함수가 아무 인자를 가지지 않을 때 제공됩니다 (여기에는 인자를 넘길 방법이 없습니다!).</p> + +<div class="note"> +<p><strong>Note</strong>: 우리는 템플릿 내에서 함수를 호출할 때 발생하는 부작용을 조금 조심해야 합니다. 여기서 우리는 그저 표시하기 위해 URL을 얻었지만, 함수는 그보다 더한 작업도 할 수 있습니다 — (예를 들면) 우리는 그냥 템플릿을 렌더링한다고 해서 우리의 데이터베이스를 삭제하고 싶지 않을 것입니다.</p> +</div> + +<h4 id="베이스_템플릿_업데이트">베이스 템플릿 업데이트</h4> + +<p>베이스 템플릿(<strong>/locallibrary/catalog/templates/<em>base_generic.html</em></strong>)을 열고 <strong>All books</strong>의 URL 링크 부분에 <strong>{% url 'books' %}</strong> 코드를 삽입하세요. 이건 모든 페이지 링크에 적용될 것입니다 (우리는 "books" url mapper를 만들었으니 이렇게 넣을 수 있습니다.)</p> + +<pre class="brush: python"><li><a href="{% url 'index' %}">Home</a></li> +<strong><li><a href="{% url 'books' %}">All books</a></li></strong> +<li><a href="">All authors</a></li></pre> + +<h3 id="어떻게_보일까요">어떻게 보일까요?</h3> + +<p>우리는 아직 도서 목록을 표시할 수 없습니다. 왜냐면 디펜던시(dependency)가 없기 떄문이죠. 책의 상세 페이지에 대한 URL이 필요한데, 이 URL은 각 도서에 대한 하이퍼 링크입니다. 다음 섹션 이후에는 목록보기와 상세보기가 모두 표시될 것입니다.</p> + +<h2 id="Book_상세_페이지">Book 상세 페이지</h2> + +<p>URL <code>catalog/book/<em><id></em></code> ( <code><em><id></em></code> 는 book의 primary key입니다)에 접근해서, Book의 상세 페이지는 특정 책의 정보를 보여줄 것입니다. <code>Book</code> 모델 (author, summary, ISBN, language, 그리고 genre) 같은 필드에 추가로, 우리는 가능한 복사본(<code>BookInstances</code>) 의 상세부분, 즉 상태와 기대하는 반납일, 기록 그리고 아이디 등을 리스트화 할 것입니다. 이렇게 하면 독자들이 책의 리스트를 확인할 뿐만 아니라, 언제 책을 대여할 수 있는지에 대한 여부를 확인할 수 있게 해줍니다.</p> + +<h3 id="URL_매핑">URL 매핑</h3> + +<p><strong>/catalog/urls.py</strong> 파일을 열고 아래 두꺼운 글씨로 된 <strong>book-detail </strong>URL mapper를 추가하세요. <code>path()</code> 함수는 연관된 제네릭 클래스 기반의 상세 뷰와 이름에 대한 패턴을 정의합니다.</p> + +<pre class="brush: python">urlpatterns = [ + path('', views.index, name='index'), + path('books/', views.BookListView.as_view(), name='books'), +<strong> path('book/<uuid:pk>', views.BookDetailView.as_view(), name='book-detail'),</strong> +]</pre> + +<p><em>book-detail URL 패턴은 우리가 원하는 책의 id를 캡처하기 위해 특별한 구문을 사용합니다. 구문은 간단합니다: 꺾쇠 괄호는 </em>캡처하는 URL의 일부를 정의하고 뷰가 캡처 된 데이터에 액세스하는 데 사용할 수있는 변수의 이름을 지정합니다. <em>예를 들어, </em><strong style="font-size: 1rem; letter-spacing: -0.00278rem;"><something></strong><span style="font-size: 1rem; letter-spacing: -0.00278rem;">은 패턴을 캡처해서 "something"이라는 변수에 데이터를 담아 전달합니다. 우리는 선택적으로 변수 이름 앞에 데이터 형식 (int, str, slug, uuid, path)을 정의하는 </span><a href="https://docs.djangoproject.com/en/2.0/topics/http/urls/#path-converters" style="font-size: 1rem; letter-spacing: -0.00278rem;">converter specification</a><span style="font-size: 1rem; letter-spacing: -0.00278rem;">을 사용할 수 있습니다.</span></p> + +<p>여기에서 우리는 book id을 캡쳐하기 위해 <code>'<uuid:pk>'</code><strong> </strong> 라는 특별히 포맷화된 문자열을 활용할 것입니다. 그리고 <code>pk</code> (primary key의 단축어)라는 이름의 파라미터로서 뷰로 넘겨줄 것입니다. This is the id that is being used to store the book uniquely in the database, as defined in the Book Model.</p> + +<p>(번역 봉사자 주: uuid를 읽지 못한다면[NoReverseMatch] <int:pk>로 해보십시오.)</p> + +<div class="note"> +<p><strong>Note</strong>: 앞에서 언급했듯이, 관련된 URL 은 실제로는 <code>catalog/book/<digits></code> 입니다.(우리가 <strong>catalog</strong> application 에 있기때문에, <code>/catalog/</code> 를 가정합니다).</p> +</div> + +<div class="warning"> +<p><strong>명심</strong>: 통상 class-based detail view 는 <strong>pk </strong>라는 이름을 가진 파라미터로 전달됩니다. 만일 자체적으로 function view 를 만든다면 어떤 이름이라도 사용 가능합니다. 혹은 이름이 없는 argument 에 정보를 넣어 전달 할 수도 있습니다.</p> +</div> + +<h4 id="Regular_expression_을_이용한_고급_path_matching">Regular expression 을 이용한 고급 path matching</h4> + +<div class="note"> +<p><strong>Note</strong>: 튜터리얼과는 관련 없습니다. 하지만 향후 Django 스타일로 개발하기 위해선 매우 유용한 팁입니다.</p> +</div> + +<p><code>path()</code> 를 이용한 패턴 검색은 간단하고 일반적인 경우 - 예를 들어 단지 특정 문자열이나 숫자가 있는지 - 매우 유용합니다. 만일 좀더 세밀한 조건 - 예를 들어 특정 문자열 길이를 갖는 문자열 검색 - 으로 검색 하고자 한다면 . <a href="https://docs.djangoproject.com/en/2.0/ref/urls/#django.urls.re_path">re_path()</a> 를 사용하길 권고 드립니다.</p> + +<p>re_path() 는 <a href="https://docs.python.org/3/library/re.html">Regular expression</a> 을 사용한다는 점만 빼고 path() 와 똑 같습니다. 예를 들어 앞서 서술한 path 는 다음과 같이 re_path 로 대체 사용 가능합니다.</p> + +<pre class="brush: python"><strong>re_path(r'^book/(?P<pk>\d+)$', views.BookDetailView.as_view(), name='book-detail'),</strong> +</pre> + +<p><em>Regular expressions</em> 은 정말로 파워풀한 매핑 툴 입니다. 하지만 솔직히 직관적이지 못하고 초보자에게는 두려운 존재입니다. 아래는 간단한 지침서 입니다!</p> + +<p>첫번째로 regular expressions 은 the raw string literal syntax 로 선언되어야 합니다 (즉, 다음처럼 '< >' 로 닫혀 있어야 한다는 겁니다: <strong>r'<your regular expression text goes here>'</strong>).</p> + +<p>패턴 매칭을 정의하기 위해 알아야 될 문법의 핵심적인 부분들입니다:</p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Symbol</th> + <th scope="col">Meaning</th> + </tr> + </thead> + <tbody> + <tr> + <td>^</td> + <td>기술된 text 로 그 문자열이 시작되는지</td> + </tr> + <tr> + <td>$</td> + <td>기술된 text 로 그 문자열이 끝나는지</td> + </tr> + <tr> + <td>\d</td> + <td>숫자(0, 1, 2, ... 9) 인지</td> + </tr> + <tr> + <td>\w</td> + <td>word character 인지. 즉, 대소문자, 숫자, underscore character (_) 로만 구성된 단어인지.</td> + </tr> + <tr> + <td>+</td> + <td>하나 이상의 선행 문자가 있는지. 예를 들어, 하나 이상의 숫자와 매치한다면 <code>\d+</code>.를 하나 이상의 'a' 문자와 매치 한다면 <code>a+</code></td> + </tr> + <tr> + <td>*</td> + <td>매치되는 문자열이 없거나 많은 경우, 예를 들어 매칭이 안되거나 한 단어를 찾고자 할 경우 <code>\w*</code></td> + </tr> + <tr> + <td>( )</td> + <td>괄호안에 있는 패턴의 일부를 선택할때. 선택된 값은 unnamed parameter 로 view 에게 전달된다. (만일 여러 패턴들이 선택 되었다면 선택된 순서대로 연관된 파라미터로써 전달 될것입니다.</td> + </tr> + <tr> + <td>(?P<<em>name</em>>...)</td> + <td>(...에 표기된) 패턴을 명명한 variable로 변환합니다(이 경우에는 "name" 입니다). 변환한 이름을 view 에 지정한 이름으로 넘깁니다. 그러므로 당신의 view 에서는 반드시 argument명을 동일하게 해주어야 합니다!</td> + </tr> + <tr> + <td>[ ]</td> + <td>집합 set 안에 있는 글자중 한개와 매치 될때. 예를 들어 [abc] 는 'a',혹은 'b' 혹은 'c' 와 매치되는지. [-\w] 는 '-' 한 글자 인지 혹은 '-'를 포함한 단어와 매치 하는지를 나타냅니다.</td> + </tr> + </tbody> +</table> + +<p>대부분의 다른 글자들은 문자 그대로 받아 들여 집니다!</p> + +<p>몇 가지 실제 패턴 예제를 보도록 합시다: </p> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Pattern</th> + <th scope="col">Description</th> + </tr> + </thead> + <tbody> + <tr> + <td><strong>r'^book/(?P<pk>\d+)$'</strong></td> + <td> + <p>이것은 우리가 URL mapper에서 사용한 Regular Expression입니다. 이 표현식은 먼저 문자열이 <code>book/</code> 으로 시작하는지 검사하고 (<strong>^book/</strong>), 그 다음에 한 개이상의 숫자가 오는지 (<code>\d+</code>), 그리고 문자열이 끝나기 전에 숫자가 아닌 문자가 들어 있지는 않는 지 검사합니다.</p> + + <p>또한 이 표현식은 모든 숫자들을 변환하고 <strong>(?P<pk>\d+)</strong> 변환된 값을 view 에 'pk'라는 이름의 parameter로 넘깁니다.<strong> 변환된 값은 항상 String type으로 넘어갑니다</strong><strong>!</strong></p> + + <p>예를 들어, 이 표현식은 <code>book/1234</code> 을 매칭합니다. 그리고 변수 <code>pk='1234'</code> 를 view에 넘깁니다.</p> + </td> + </tr> + <tr> + <td><strong>r'^book/(\d+)$'</strong></td> + <td>이 표현식은 위의 표현식과 동일한 URL들을 매칭합니다. 변환된 정보는 명명되지 않은 argument로 view에 전달됩니다.</td> + </tr> + <tr> + <td><strong>r'^book/(?P<stub>[-\w]+)$'</strong></td> + <td> + <p>이 표현식은 문자열 처음 부분에 <code>book/</code> 으로 시작하는지 검사하고 (<strong>^book/</strong>), 그리고 한 개 또는 그 이상의 '-' 나 word character가 오고 (<strong>[-\w]+</strong>), 그렇게 끝내는지를 매칭합니다. 이 표현식 또한 매칭된 부분을 변환하고 view 에 'stub' 라는 이름의 parameter로 전달합니다.</p> + + <p>This is a fairly typical pattern for a "stub". Stubs are URL-friendly word-based primary keys for data. You might use a stub if you wanted your book URL to be more informative. For example <code>/catalog/book/the-secret-garden</code> rather than <code>/catalog/book/33</code>.</p> + </td> + </tr> + </tbody> +</table> + +<p>당신은 다양한 패턴들을 한번의 매칭을 통해 변환시킬 수 있습니다. 그러므로 다양한 정보들을 URL안에 인코딩할 수 있습니다.</p> + +<div class="note"> +<p><strong>Note</strong>: 추가적으로, 특정 날짜에 출간된 책 목록을 URL에 인코딩할 수 있을지 생각해보세요. 그리고 어떤 Regular Expression이 해당 URL을 매칭할 수 있을까요?</p> +</div> + +<h4 id="Passing_additional_options_in_your_URL_maps">Passing additional options in your URL maps</h4> + +<p>우리가 여태까지 사용하지는 않았지만, 쓸모있을만한 한 기능은 당신이 <a href="https://docs.djangoproject.com/en/2.0/topics/http/urls/#views-extra-options">additional options</a> 을 정의내리고 view에 전달할 수 있다는 것입니다. 이 option들은 dictionary 형태로 정의하고 <code>path()</code> 함수의 3번째 명명되지 않은 argument로 전달됩니다. 이 방식은 만약, 당신이 동일한 view 를 다른 곳에서 재활용하려고 하거나, 각 상황에 맞게 조절하려고 할 때 유용합니다. (이 경우, 우리는 각 경우에 따라 다른 template 을 제공합니다).</p> + +<pre class="brush: python">path('url/', views.my_reused_view, <strong>{'my_template_name': 'some_path'}</strong>, name='aurl'), +path('anotherurl/', views.my_reused_view, <strong>{'my_template_name': 'another_path'}</strong>, name='anotherurl'), +</pre> + +<div class="note"> +<p><strong>Note:</strong> 추가된 options 과 변환된 패턴들 중 명명된 것들은 view 에 명명된 arguments로 전달됩니다. 만약 당신이<strong> 동일한 이름을</strong> 변환된 패턴들과 추가적인 option에 사용한다면, 오직 변환된 패턴들만이 view에 보내지게 됩니다. ( 추가된 option들에 있는 값들은 모두 버려집니다). </p> +</div> + +<h3 id="뷰_(클래스_기반)">뷰 (클래스 기반)</h3> + +<p><strong>catalog/views.py </strong>을 열고, 다음 코드를 파일 끝에 넣으세요:</p> + +<pre class="brush: python">class BookDetailView(generic.DetailView): + model = Book</pre> + +<p>다됬습니다! 이제 해야될 일은 <strong>/locallibrary/catalog/templates/catalog/book_detail.html </strong>template를 만들면, view는 template에 URL mapper에 의해 찾고자 하는 데이터베이스에 있는 특정 <code>Book </code> 레코드의 정보를 전달할 겁니다. template 안에서 template 변수 <code>object</code> 또는 <code>book</code>(즉, 일반적으로는 "<font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">해당_모델_명</span></font>") 으로 책 목록에 접근할 수 있습니다.</p> + +<p>만약 필요하다면, 사용하고 있는 template 또는 template 안에서 book을 참조하는 데 사용되는 context object의 이름을 바꿀 수 있습니다. 또한, 예를 들어 context에 정보를 추가하는 식으로, 메서드를 오버라이드 할 수도 있습니다.</p> + +<h4 id="만약_해당_레코드가_존재하지_않는다면_무슨_일이_일어날까요">만약 해당 레코드가 존재하지 않는다면 무슨 일이 일어날까요?</h4> + +<p>만약 요청된 레코드가존재하지 않는다면, 제네릭 클래스 기반의 detail view는 <code>Http404</code> exception 이 저절로 발생할 것입니다. — 만들어질 때, 적절한 "resource not found" 페이지를 알아서 보여줄 것입니다. 만약 원한다면 당신이 해당 페이지를 수정할 수 있겠죠.</p> + +<p>이런 일이 어떻게 발생하는지 원리를 조금 알려줄게요. 밑에 있는 코드는 만약 당신이 제네릭 클래스 기반의 detail view를 <strong>사용하지 않는다면</strong>, 클래스 기반의 view를 어떻게 함수 형태로 표현 할 수 있는지 보여줍니다.</p> + +<pre class="brush: python">def book_detail_view(request, primary_key): + try: + book = Book.objects.get(pk=primary_key) + except Book.DoesNotExist: + raise Http404('Book does not exist') + + return render(request, 'catalog/book_detail.html', context={'book': book}) +</pre> + +<p>view는 먼저 model로 부터 특정 book 의 레코드를 얻으려고 할 것입니다. 이 시도가 실패하면, view 는 "해당 책이 존재하지 않음"을 알려주면서 <code>Http404</code> exception가 발생할 것입니다. 그리고 마지막 과정은 ,평소처럼, book 정보를 <code>context</code> parameter (dictionary 형태로)에 집어 넣고 template 이름과 함께 <code>render()</code> 함수를 호출 할 것입니다.</p> + +<p>혹, 만약 해당 레코드를 찾지 못한다면, 우리는 손쉬운 방법으로 <code>Http404</code> exception을 발생하기 위해<code>get_object_or_404()</code> 함수를 사용할 수도 있어요.</p> + +<pre class="brush: python">from django.shortcuts import get_object_or_404 + +def book_detail_view(request, primary_key): + book = get_object_or_404(Book, pk=primary_key) + return render(request, 'catalog/book_detail.html', context={'book': book})</pre> + +<h3 id="상세_뷰_템플릿_생성하기">상세 뷰 템플릿 생성하기</h3> + +<p><strong>/locallibrary/catalog/templates/catalog/book_detail.html </strong>파일을 만들고, 아래 텍스트를 복사 붙여넣기 하세요. 위에서 설명한대로, 이 파알명은 제네릭 클래스 기반 상세 뷰의 디폴트 파일명입니다. (<code>catalog</code> 애플리케이션의 <code>Book</code> 모델을 위한 상세 뷰)</p> + +<pre class="brush: html">{% extends "base_generic.html" %} + +{% block content %} + <h1>Title: \{{ book.title }}</h1> + + <p><strong>Author:</strong> <a href="">\{{ book.author }}</a></p> <!-- author detail link not yet defined --> + <p><strong>Summary:</strong> \{{ book.summary }}</p> + <p><strong>ISBN:</strong> \{{ book.isbn }}</p> + <p><strong>Language:</strong> \{{ book.language }}</p> + <p><strong>Genre:</strong> {% for genre in book.genre.all %} \{{ genre }}{% if not forloop.last %}, {% endif %}{% endfor %}</p> + + <div style="margin-left:20px;margin-top:20px"> + <h4>Copies</h4> + + {% for copy in book.bookinstance_set.all %} + <hr> + <p class="{% if copy.status == 'a' %}text-success{% elif copy.status == 'm' %}text-danger{% else %}text-warning{% endif %}">\{{ copy.get_status_display }}</p> + {% if copy.status != 'a' %} + <p><strong>Due to be returned:</strong> \{{copy.due_back}}</p> + {% endif %} + <p><strong>Imprint:</strong> \{{copy.imprint}}</p> + <p class="text-muted"><strong>Id:</strong> \{{copy.id}}</p> + {% endfor %} + </div> +{% endblock %}</pre> + +<ul> +</ul> + +<div class="note"> +<p>이 템플릿의 작가 링크는 비어있는 URL입니다. 왜냐면 우리는 아직 작가 상세 페이지를 만들지 않았기 때문이죠. 만약 페이지가 존재한다면, URL을 아래와 같이 업데이트 해야합니다.</p> + +<pre><a href="<strong>{% url 'author-detail' book.author.pk %}</strong>">\{{ book.author }}</a> +</pre> +</div> + +<p>조금 더 커졌지만, 이 템플릿의 대부분의 것들은 이미 언급된 것들입니다:</p> + +<ul> + <li>content 블럭을 오버라이드 해서 우리의 기본 템플릿을 extend하였습니다.</li> + <li>우리는 조건 판단 처리를 해서 특정 컨텐츠가 있을지 없는지 체크하여 표시합니다.</li> + <li><code>for</code> 루프를 활용하여 objects들의 리스트를 표현합니다.</li> + <li>우리는 context fields를 dot notation를 활용합니다 (왜냐하면 우리는 detail generic view를 사용하는데, context의 이름은 <code>book</code> 이기에 우리는 "<code>object</code>"를 사용할 수 있습니다)</li> +</ul> + +<p>우리가 본 적 없는 한가지 흥미로운 점은 바로 <code>book.bookinstance_set.all()</code> 함수입니다. 이 메소드는 Django에 의해 자동으로 만들어진 메소드입니다. 이 메소드는 <code>Book</code> 과 관련된 <code>BookInstance</code> 레코드 집합을 반환합니다. </p> + +<pre class="brush: python">{% for copy in book.bookinstance_set.all %} + <!-- code to iterate across each copy/instance of a book --> +{% endfor %}</pre> + +<p>이 메소드는 관계의 한쪽("one")에만 <code>ForeignKey</code>(one-to many) 필드를 선언했기 때문에 필요합니다. 다른("many") 모델에서 아무것도 선언하지 않았기 때문에 관련 레코드 집합을 가져올 필드가 없습니다. 이 문제를 해결하기 위해, Django는 지금 우리가 사용하고 있는 "reverse lookup"이라는 적당한 이름의 함수를 만들었습니다. 이 함수의 이름은 <code>ForeignKey</code>가 선언되어있는 모델 이름을 소문자로 만들고, 그 뒤에 <code>_set</code>을 붙이면 됩니다. (따라서 <code>Book</code>에서 만든 함수는 <code>bookinstance_set()</code>가 되겠죠.)</p> + +<div class="note"> +<p><strong>Note</strong>: 여기서 우리는 모든 레코드를 가져오기 위해 <code>all()</code> 을 사용했습니다(기본값이죠). 반대로 당신은 <code>filter()</code> 메서드를 사용해서 레코드의 부분 집합을 가져올 수 있지만, 당신은 template에서 이걸 직접할 수는 없어요. 왜냐하면 함수의 arguments를 정할 수 없으니까요.</p> + +<p>만약 순서를 정의하지 않는다면 (클래스 기반 view 또는 model에서), 당신은 개발 서버로 부터 다음과 같은 에러를 받게 될 거라는 것 또한 알아두세요.</p> + +<pre>[29/May/2017 18:37:53] "GET /catalog/books/?page=1 HTTP/1.1" 200 1637 +/foo/local_library/venv/lib/python3.5/site-packages/django/views/generic/list.py:99: UnorderedObjectListWarning: Pagination may yield inconsistent results with an unordered object_list: <QuerySet [<Author: Ortiz, David>, <Author: H. McRaven, William>, <Author: Leigh, Melinda>]> + allow_empty_first_page=allow_empty_first_page, **kwargs) +</pre> + +<p>이것은 <a href="https://docs.djangoproject.com/en/2.0/topics/pagination/#paginator-objects">paginator object</a> 가 데이터베이스에서 ORDER BY 명령어가 실행되었을 것이라고 예상하기 때문에 발생하는 것입니다. 이러한 것이 없다면, 레코드들이 정확한 순서로 반환되었는지 알 수가 없어요!<strong> </strong></p> + +<p>이 튜토리얼은 아직 <strong>Pagination</strong> 에 도달하지는 않았습니다.(곧 하게될 거에요) <code>sort_by()</code> 에 parameter를 전달하여 사용하는 것은 (위에서 이야기했던 <code>filter()</code> 와 동일한 역할을 합니다.) 사용할 수 없기 때문에, 당신은 3개의 선택권중에 하나를 골라야합니다:</p> + +<ol> + <li>Add a <code>ordering</code> inside a <code>class Meta</code> declaration on your model.</li> + <li>Add a <code>queryset</code> attribute in your custom class-based view, specifying a <code>order_by()</code>.</li> + <li>Adding a <code>get_queryset</code> method to your custom class-based view and also specify the <code>order_by()</code>.</li> +</ol> + +<p>만약 <code>Author</code> model에 <code>class Meta</code> 사용하기를 결정했다면 (커스터마이징 된 클래스 기반 view만큼 유연하진 않겠지만, 쉬운 방법입니다), 아마 밑에 코드와 비슷하게 끝날 거에요:</p> + +<pre>class Author(models.Model): + first_name = models.CharField(max_length=100) + last_name = models.CharField(max_length=100) + date_of_birth = models.DateField(null=True, blank=True) + date_of_death = models.DateField('Died', null=True, blank=True) + + def get_absolute_url(self): + return reverse('author-detail', args=[str(self.id)]) + + def __str__(self): + return f'{self.last_name}, {self.first_name}' + +<strong> class Meta: + ordering = ['last_name']</strong></pre> + +<p>물론, 해당 field는 <code>last_name</code> 이어야 할 필요는 없습니다: 다른 어떤 것도 될 수 있어요.</p> + +<p>마지막으로, 그러나 적어도 우리는 정렬(sort)을 attribute/column에 따라 해줘야 합니다. unique 여부와 상관없이 당신의 database의 퍼포먼스 이슈를 위해서 필요합니다. 물론, 이것은 여기서 필요한 것이 아니며 어떻게 보면 약간 진도를 앞서나가는 것 같지만 이런 작은 사용자와 프로젝트에서도 미래의 프로젝트를 위해서 미리 명심해 두는 것이 좋습니다.</p> +</div> + +<h2 id="어떻게_보일까요_2">어떻게 보일까요?</h2> + +<p>이 시점에서 책 목록 페이지와 책 세부 사항 페이지를 보기 위한 모든 것을 만들어 놓았어야 합니다. 명령어 (<code>python3 manage.py runserver</code>) 를 입력하여 서버를 실행하고 브라우저를 열어 <a href="http://127.0.0.1:8000/">http://127.0.0.1:8000/</a> 에 접속해보세요.</p> + +<div class="warning"> +<p><strong>주의!:</strong> 아직 작가 목록 페이지나 작가 세부 사항 페이지를 클릭하시면 안됩니다. — 당신은 challenge에서 이것들을 만들어보게 될 거에요!</p> +</div> + +<p>책 목록을 보기 위해 <strong>All books</strong> 링크를 클릭하세요. </p> + +<p><img alt="Book List Page" src="https://mdn.mozillademos.org/files/14049/book_list_page_no_pagination.png" style="border-style: solid; border-width: 1px; display: block; height: 216px; margin: 0px auto; width: 823px;"></p> + +<p>그리고 당신의 책들 중 하나를 클릭해보세요. 만약, 현재까지의 과정을 성공적으로 따라왔다면, 당신은 다음과 같은 스크린샷을 볼 수 있을 겁니다.</p> + +<p><img alt="Book Detail Page" src="https://mdn.mozillademos.org/files/14051/book_detail_page_no_pagination.png" style="border-style: solid; border-width: 1px; display: block; height: 783px; margin: 0px auto; width: 926px;"></p> + +<h2 id="Pagination">Pagination</h2> + +<p>만약 레코드가 몇 개 없다면, 현재의 책 목록 페이지도 괜찮습니다. 하지만 수십,수백개의 레코드를 갖고 있다면, 페이지는 가져오는 데 점차 시간이 늘어날 겁니다(양이 너무 많아 탐색하는게 체감적으로 힘들어질 정도로요). 해결 방법은 당신의 list view에 pagination을 추가하는 것입니다, 그리고 pagination은 각 페이지마다 보여주는 항목들을 감소시켜줄 것입니다.</p> + +<p>장고는 pagination에 대한 훌륭한 지원을 하고 있습니다. 더욱 좋은 점은,이 지원은 제네릭 클래스 기반 list view에 내장되어 있어서, 당신이 pagination을 하기 위해 해야될 것이 많지 않다는 것입니다!</p> + +<h3 id="Views">Views</h3> + +<p><strong>catalog/views.py</strong>열고, 밑에 굵은 글씨로 작성되어있는 <code>paginate_by</code> 줄을 추가해주세요.</p> + +<pre class="brush: python">class BookListView(generic.ListView): + model = Book + <strong>paginate_by = 10</strong></pre> + +<p>이 것이 추가됨에 따라, 당신이 10개 이상의 레코드를 갖게 되면 view는 template에 보내는 데이터에 pagination 하는 것을 시작할 것입니다. 다른 page들을 GET parameter들을 통해 접근할 수 있습니다— 2 페이지에 접속하려면, 다음과 같은 URL을 사용하세요: <code>/catalog/books/<strong>?page=2</strong></code>.</p> + +<h3 id="Templates">Templates</h3> + +<p>자료들이 pagination되었습니다, 우리는 template에 결과들을 훑어볼 수 있도록 만들어야합니다. 우리는 이러한 기능이 모든 list view들에 필요할 수 있으므로, 우리는 base template에 추가하는 방향으로 작업을 진행하려고 합니다. </p> + +<p><strong>/locallibrary/catalog/templates/<em>base_generic.html</em></strong> 열고 content block 밑에 다음과 같은 pagination block을 복사하여 추가하세요 (아래에 굵은 글씨로 강조표시를 해놓았습니다). 첫번째로 코드는 현재 페이지가 pagination이 가능한지 체크합니다. 만약 가능하다면, 다음 페이지와 전 페이지를 적절히 추가합니다 (현재 페이지 넘버도요). </p> + +<pre class="brush: python">{% block content %}{% endblock %} + +<strong>{% block pagination %} + {% if is_paginated %} + <div class="pagination"> + <span class="page-links"> + {% if page_obj.has_previous %} + <a href="\{{ request.path }}?page=\{{ page_obj.previous_page_number }}">previous</a> + {% endif %} + <span class="page-current"> + <p>Page \{{ page_obj.number }} of \{{ page_obj.paginator.num_pages }}.</p> + </span> + {% if page_obj.has_next %} + <a href="\{{ request.path }}?page=\{{ page_obj.next_page_number }}">next</a> + {% endif %} + </span> + </div> + {% endif %} +{% endblock %} </strong></pre> + +<p>만약 현재 페이지에 pagination이 사용중이라면, <code>page_obj</code> 가 <a href="https://docs.djangoproject.com/en/2.0/topics/pagination/#paginator-objects">Paginator</a> 오브젝트 로서 존재합니다. 해당 오브젝트는 현재 페이지, 전 페이지, 페이지 수는 얼마나 되는 지등의 모든 정보를 제공합니다.</p> + +<p>pagination 링크를 만들기 위해 우리는 <code>\{{ request.path }}</code> 를 이용하여 현재 페이지의 URL을 가져오도록 할 겁니다. 우리가 pagination을 하는 객체와 독립적이기 때문에 유용합니다.</p> + +<p>다됬네요!</p> + +<h3 id="어떻게_보일_까요">어떻게 보일 까요?</h3> + +<p>밑에 있는 스크린샷은 pagination이 어떻게 보이는지를 알려줍니다 — 만약 에디터베이스에 10개가 넘는 제목을 추가하지 않았다면, <strong>catalog/views.py</strong> 파일에 있는 <code>paginate_by</code> 줄에 있는 숫자를 낮춤으로써 쉽게 테스트할 수 있습니다. 밑에 있는 결과는 우리가 <code>paginate_by = 2</code>로 바꾼 겨로가입니다.</p> + +<p>next/previous 링크와 함께 보이는 밑에 pagination 링크는 당신이 어느 페이지에 있느냐에 따라 달리 표시가 됩니다. </p> + +<p><img alt="Book List Page - paginated" src="https://mdn.mozillademos.org/files/14057/book_list_paginated.png" style="border-style: solid; border-width: 1px; display: block; height: 216px; margin: 0px auto; width: 924px;"></p> + +<h2 id="도전과제">도전과제</h2> + +<p>이번 글의 과제는 프로젝트를 완수하기 위해 필요한 작가 세부 사항과 목록 view들을 만드는 것입니다. 이 과제를 통해 해당 URL들을 사용가능하게 만들어야 해요:</p> + +<ul> + <li><code>catalog/authors/</code> — 작가 목록.</li> + <li><code>catalog/author/<em><id></em></code><em> </em>—<em><code><id></code></em>라는 이름의 기본키를 이용한 작가의 세부 사항</li> +</ul> + +<p>URL mappers에 필요한 코드들과 view들은 ,사실상, 우리가 위에서 만들었던 <code>Book</code> 목록과 세부 사항 view들과 동일해야 합니다. template들은 다르겠지만, 비슷한 동작을 가지고 있을 겁니다.</p> + +<div class="note"> +<p><strong>Note</strong>:</p> + +<ul> + <li>작가 목록 페이지를 위한 URL mapper를 만들고나면, <strong>All authors</strong> base template에 있는 <strong>All authors </strong>링크 또한 업데이트 해야될 필요를 느끼게 될 겁니다. 우리가 <strong>All books </strong>링크 업데이트 때 했던, <a href="#Update_the_base_template">수행 과정</a>을 따라해주세요.</li> + <li>작가 세부 사항 페이지에 대한 URL mapper를 만들고나면, 당신은 <a href="#Creating_the_Detail_View_template">book detail view template</a> (<strong>/locallibrary/catalog/templates/catalog/book_detail.html</strong>) 또한 업데이트 해야 합니다. 그래야 작가 링크가 당신이 새로 만든 작가 세부 사항 페이지를 가리키거든요. (비어 있는 URL로 있기 보다는 말이죠). 굵게 되어 있는 부분을 template 내의 태그에 넣어주세요. + <pre class="brush: html"><p><strong>Author:</strong> <a href="<strong>{% url 'author-detail' book.author.pk %}</strong>">\{{ book.author }}</a></p> +</pre> + </li> +</ul> +</div> + +<p>모두 마치면, 당신의 페이즈들은 아마 밑의 스크린샷과 비슷하게 보일 겁니다.</p> + +<p><img alt="Author List Page" src="https://mdn.mozillademos.org/files/14053/author_list_page_no_pagination.png" style="border-style: solid; border-width: 1px; display: block; margin: 0px auto;"></p> + +<ul> +</ul> + +<p><img alt="Author Detail Page" src="https://mdn.mozillademos.org/files/14055/author_detail_page_no_pagination.png" style="border-style: solid; border-width: 1px; display: block; height: 358px; margin: 0px auto; width: 825px;"></p> + +<ul> +</ul> + +<h2 id="요약">요약</h2> + +<p>축하합니다, 도서관의 가장 기본적인 기능들은 모두 끝났어요! </p> + +<p>이번 글에서, 우리는 제네릭 클래스 기반의 list view와 detailv view에 대해서 배웠고, 이를 이용하여 책들과 작가들을 보여주기 위한 페이지를 만들었습니다. 이 과정중에 우리는 정규표현식을 이용하여 패턴 매칭을 하는 것도 배웠고, URL로 부터 데이터를 view에 보내는 것도 배웠습니다. 또한, template을 이용하는 몇 가지 트릭도 배웠죠. 마지막에는 list views에 어떻게 paginate를 할 수 있는지도 보았습니다. 이로 인해 우리는 레코드들이 많아져도 리스트를 관리할 수 있게 되었습니다.</p> + +<p>다음 글에서 우리는 유저 계정을 지원하도록 도서관을 확장하고, 이를 통해 유저 인증, 권한, 세션, forms을 볼 것입니다.</p> + +<h2 id="See_also">See also</h2> + +<ul> + <li><a href="https://docs.djangoproject.com/en/2.0/topics/class-based-views/generic-display/">Built-in class-based generic views</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.0/ref/class-based-views/generic-display/">Generic display views</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.0/topics/class-based-views/intro/">Introduction to class-based views</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.0/ref/templates/builtins">Built-in template tags and filters</a> (Django docs).</li> + <li><a href="https://docs.djangoproject.com/en/2.0/topics/pagination/">Pagination</a> (Django docs)</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Django/Home_page", "Learn/Server-side/Django/Sessions", "Learn/Server-side/Django")}}</p> + +<p> </p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Server-side/Django/Introduction">Django introduction</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/development_environment">Setting up a Django development environment</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Django Tutorial: The Local Library website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django Tutorial Part 2: Creating a skeleton website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Models">Django Tutorial Part 3: Using models</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Admin_site">Django Tutorial Part 4: Django admin site</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django Tutorial Part 5: Creating our home page</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Generic_views">Django Tutorial Part 6: Generic list and detail views</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Sessions">Django Tutorial Part 7: Sessions framework</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Authentication">Django Tutorial Part 8: User authentication and permissions</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Forms">Django Tutorial Part 9: Working with forms</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Testing">Django Tutorial Part 10: Testing a Django web application</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Django Tutorial Part 11: Deploying Django to production</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/web_application_security">Django web application security</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></li> +</ul> + +<p> </p> diff --git a/files/ko/learn/server-side/django/home_page/index.html b/files/ko/learn/server-side/django/home_page/index.html new file mode 100644 index 0000000000..25c67b7949 --- /dev/null +++ b/files/ko/learn/server-side/django/home_page/index.html @@ -0,0 +1,414 @@ +--- +title: 'Django Tutorial Part 5: Creating our home page' +slug: Learn/Server-side/Django/Home_page +translation_of: Learn/Server-side/Django/Home_page +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Django/Admin_site", "Learn/Server-side/Django/Generic_views", "Learn/Server-side/Django")}}</div> + +<p class="summary">우리는 이제 첫 전체 페이지를 보여주는 코드를 추가할 때가 되었습니다 — <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a> website를 위한 홈페이지를요. 이 홈페이지는 각각의 모델 타입마다 갖고 있는 레코드들의 숫자를 보여주고, 우리의 다른 페이지들로 이동할 수 있는 사이드바 내비게이션 링크들을 제공합니다. 이 섹션에서 우리는 기본 URL 맵과 뷰들을 작성하고, 데이터베이스에서 레코드들을 가져오고 그리고 탬플릿을 사용하는 것에 대한 연습 경험을 가질 수 있습니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">사전 준비:</th> + <td><a href="/en-US/docs/Learn/Server-side/Django/Introduction">Django Introduction</a>을 읽어보세요. 이전 튜토리얼들을 완료하세요 (<a href="/en-US/docs/Learn/Server-side/Django/Admin_site">Django Tutorial Part 4: Django admin site</a> 포함).</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>간단한 url 맵과 뷰를 생성하고(URL 안에 아무런 데이터도 인코드되지 않은), 모델로부터 데이터를 가져오고, 탬플릿을 생성하는 방법을 배우기.</td> + </tr> + </tbody> +</table> + +<h2 id="개요">개요</h2> + +<p>지금까지는 우리의 모델을 정의하고 약간의 초기 도서관 레코드들을 만들어 왔고, 이제는 사용자에게 정보를 제공하기 위한 코드를 작성할 때입니다. 첫 번째 우리가 할 일은 우리의 페이지에서 어떤 정보를 보여줄 것인지를 결정하고, 그 요소들을 반환하는 데 사용되는 URL들을 정의하는 것입니다. 다음으로 우리는 페이지를 나타내기 위한 URL 매퍼, views, 그리고 탬플릿들을 생성할 것입니다. </p> + +<p> 아래 다이어그램은 주요 데이터 흐름 그리고 HTTP 요청과 응답을 처리하는 데 필요한 요소들을 보여줍니다. 모델은 이미 구현되었기 떄문에, 우리가 생성할 주요 요소들은 다음과 같습니다:</p> + +<ul> + <li>URL 매퍼들 : 적절한 view 함수들을 위해 지원되는 URL들(그리고 URL들 안에 인코딩된 어떤 정보라도)을 포워딩하기 위해.</li> + <li>View 함수들: 요청된 데이터를 모델들에게서 가져오고, 데이터를 표시하는 HTML 페이지를 생성하고 그리고 브라우저 안의 view로 페이지들을 사용자에게 반환하기 위해.</li> + <li>탬플릿들: 데이터를 뷰들 안에 렌더링할 때 사용하기 위해.</li> +</ul> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13931/basic-django.png" style="display: block; margin: 0px auto;"></p> + +<p> 우리가 표시해야 할 페이지는 총 다섯 페이지입니다. 하나의 글에 담기에는 너무 많은 정보죠. 따라서, 이 글의 대부분은 홈 페이지를 어떻게 구현하는 지에 대해 집중하고, 다음 글에서 다른 페이지들에 대해 다루겠습니다. 이렇게 하면 URL 매퍼들, view들, 그리고 모델이 실제로 작동하는 방식에 대해 완벽하고 철저하게 이해할 수 있을 것입니다.</p> + +<h2 id="resource_URLs_정의하기">resource URLs 정의하기</h2> + +<p>이 버전의 LocalLibrary는 근본적으로 최종 사용자들에게는 읽기 전용이기 때문에, 우리는 사이트의 방문 페이지(홈 페이지) 그리고 책들과 저자들에 대한 목록 및 세부 view들을 보여주는 페이지만 제공하면 됩니다. </p> + +<p>우리의 페이지들을 위해 필요한 URL들은:</p> + +<ul> + <li><code>catalog/</code> — 홈/색인(index) 페이지.</li> + <li><code>catalog/books/</code> — 모든 책들의 목록.</li> + <li><code>catalog/authors/</code> — 모든 저자들의 목록.</li> + <li><code>catalog/book/<em><id></em></code> — <code><em><id></em></code> 라는 이름의(기본값) 프라이머리 키(primary key) 필드를 가지는 특정한 책을 위한 세부 사항 뷰(detail view). 예를 들어, 목록에 추가된 세 번째 책은 <code>/catalog/book/3</code>이 될 것입니다. </li> + <li><code>catalog/author/<em><id></em></code><em> </em>— <code><em><id></em></code> 라는 이름의 프라이머리 키(primary key) 필드를 가지는 특정한 저자를 위한 세부 사항 뷰(detail view). 예를 들어, 목록에 추가된 11번째 저자는 <code>/catalog/author/11</code>이 될 것입니다.</li> +</ul> + +<p>처음 세 개의 URL들은 인덱스 페이지, 책 목록, 그리고 저자 목록을 반환합니다. 이것들은 아무런 추가적인 정보도 인코드하지 않고, 데이터베이스에서 데이터를 가져오는 쿼리들도 항상 똑같습니다. 그러나, 쿼리들이 반환할 결과들은 데이터베이스의 내용물에 따라 다를 것입니다.</p> + +<p>그에 반해서 마지막 두 개의 URL들은 특정한 책 또는 저자에 대한 세부 정보를 나타낼 것입니다. 이 URL들은 표시할 항목의 ID를 인코딩합니다(위에서 <code><em><id></em></code> 로 표시). URL 매퍼는 인코딩된 정보를 추출하여 view로 전달합니다. 그리고 view는 데이터베이스에서 무슨 정보를 가져올지 동적으로 결정합니다. URL의 정보를 인코딩하여 우리는 모든 책들(또는 저자들)을 처리하기 위해 단일 모임의 url 매핑, 뷰, 탬플릿을 사용할 것입니다. </p> + +<div class="note"> +<p><strong>주의:</strong> 장고를 이용해서 당신이 필요로 하는 대로 URL들을 만들 수 있습니다 — 위와 같이 URL의 본문(body)에 정보를 인코딩할 수도 있고, 또는 URL 안에 GET 매개 변수들을 포함시킬 수 있습니다(예: /book/?id=6). 어떤 방식이건 URL들은 깨끗하고, 논리적이고, 읽기 쉬워야 합니다. (<a href="https://www.w3.org/Provider/Style/URI">check out the W3C advice here</a>).<br> + 장고 문서는 더 나은 URL 설계(design)를 위해 URL의 본문(body)에 정보를 인코딩하는 것을 권장합니다.</p> +</div> + +<p>개요에서 다룬 것 처럼, 이 글의 나머지는 색인(index) 페이지를 만드는 방법을 보여줍니다.</p> + +<h2 id="index_page_만들기">index page 만들기</h2> + +<p>우리가 만들 첫 번째 페이지는 index page입니다 (<code>catalog/</code>). index 페이지는 데이터베이스 안의 서로 다른 레코드들의 생성된 "개수(count)" 와 함께 몇 가지 정적 HTML을 포함합니다. 이것이 작동하도록 하기 위해서 우리는 URL 매핑, 뷰 그리고 탬플릿을 생성하겠습니다. </p> + +<div class="note"> +<p><strong>주의</strong>:이 섹션에 조금 더 집중해 봅시다. 대부분의 정보들이 우리가 생성할 다른 페이지들에도 적용되기 때문입니다.</p> +</div> + +<h3 id="URL_매핑">URL 매핑</h3> + +<p><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">skeleton website</a>를 만들었을 때, 우리는 <strong>locallibrary/urls.py</strong> 파일을 업데이트했습니다. <code>catalog/</code>로 시작하는 URL을 받았을 때, URLConf 모듈인<em> </em><code>catalog.urls</code> 가 나머지 문자열을 처리하도록 하기 위해서죠.</p> + +<p><strong>locallibrary/urls.py</strong> 의 아래 코드 조각은 <code>catalog.urls</code> 모듈을 포함합니다:</p> + +<pre>urlpatterns += [ + path('catalog/', include('catalog.urls')), +] +</pre> + +<div class="note"> +<p><strong> 주의</strong>: 장고는 import 함수 django.urls.include()를 만날 때 마다 지정된 마지막 문자에서 문자열을 나누고, 나머지 부분 문자열을 추가 작업을 위해 포함된 URLconf 모듈로 보냅니다.</p> +</div> + +<p>우리는 또한 <strong>/catalog/urls.py</strong>로 이름지어진 URLConf 모듈을 위한 자리 표시자(placeholder) 파일도 생성했습니다. 그 파일에 아래 줄을 추가하세요</p> + +<pre class="brush: python">urlpatterns = [ +<strong> path('', views.index, name='index'),</strong> +]</pre> + +<p>이 <code>path()</code> 함수는 아래를 정의합니다 : </p> + +<ul> + <li>빈 문자열인 URL 패턴 :<code>''</code>. 다른 뷰들을 작업할 때 URL 패턴들에 관해 자세히 다룰겁니다.</li> + <li>URL 패턴이 감지되었을 때 호출될 view 함수:<code>views.index</code>. 이 함수는 <strong>views.py</strong> 파일 안에서 <code>index()</code>로 이름지어져 있습니다.</li> +</ul> + +<p>이 <code>path()</code> 함수는 또한 <code>name</code> 매개 변수를 지정합니다. 그것은 이 특정한 URL 매핑을 위한 고유 ID 입니다. 당신은 이 이름을 매퍼를 "반전" 시킬 수 있습니다. 즉, 매퍼가 처리하도록 설계된 리소스를 향하는 URL을 동적으로 생성하기 위해서죠. 예를 들자면, 우리는 아래 링크를 탬플릿에 추가해서 이름 매개 변수를 사용하여 다른 모든 페이지에서 홈 페이지로 링크를 걸 수 있습니다:</p> + +<pre class="brush: html"><a href="<strong>{% url 'index' %}</strong>">Home</a>.</pre> + +<div class="note"> +<p><strong>주의</strong>: 우리는 위 링크를 하드코딩할 수 있지만(예: <code><a href="<strong>/catalog/</strong>">Home</a></code>), 그렇게 하면 만약에 우리가 홈페이지를 바꿨을 때 (예: <code>/catalog/index</code>로 바꿨을 때) 탬플릿들은 더이상 알맞게 링크되지 않습니다. 반전된 url 매핑을 사용하는 것이 훨씬 유연하고 강력합니다.</p> +</div> + +<h3 id="View_(함수-기반의)">View (함수-기반의)</h3> + +<p>뷰는 HTTP 요청을 처리하고, 데이터베이스에서 요청된 데이터를 가져오고, HTML 탬플릿을 이용해서 데이터를 HTML 페이지에 렌더링하고 그리고 생성된 HTML을 HTTP 응답으로 반환하여 사용자들에게 페이지를 보여주는 함수입니다. 색인(index) 뷰는 이 구조(model)를 따라갑니다 — 이것은 데이터베이스 안에 있는<code>Book</code>, <code>BookInstance</code>, 사용 가능한 <code>BookInstance</code> 그리고 <code>Author</code> 레코드들의 개수에 대한 정보를 가져오고, 그 정보를 디스플레이(display)를 위해 탬플릿으로 전달합니다.</p> + +<p><strong>catalog/views.py</strong> 를 열어서, 파일이 이미 탬플릿과 데이터를 이용해 HTML 파일을 생성하는 <a href="https://docs.djangoproject.com/en/2.0/topics/http/shortcuts/#django.shortcuts.render">render()</a> 바로가기 함수를 포함(import)하고 있음을 확인하세요.</p> + +<pre class="brush: python">from django.shortcuts import render + +# Create your views here. +</pre> + +<p> 파일의 하단에 아래 코드를 복사 붙여넣기 하세요.</p> + +<pre class="brush: python">from catalog.models import Book, Author, BookInstance, Genre + +def index(request): + """View function for home page of site.""" + + # Generate counts of some of the main objects + num_books = Book.objects.all().count() + num_instances = BookInstance.objects.all().count() + + # Available books (status = 'a') + num_instances_available = BookInstance.objects.filter(status__exact='a').count() + + # The 'all()' is implied by default. + num_authors = Author.objects.count() + + context = { + 'num_books': num_books, + 'num_instances': num_instances, + 'num_instances_available': num_instances_available, + 'num_authors': num_authors, + } + + # Render the HTML template index.html with the data in the context variable + return render(request, 'index.html', context=context)</pre> + +<p>첫번째 줄은 우리의 모든 뷰들 안에서 데이터에 접근하는 데 사용할 모델 클래스들을 포함(import)합니다.</p> + +<p>view 함수의 첫번째 부분은 모델 클래스들에서 <code>objects.all()</code> 속성을 사용하는 레코드들의 개수를 가져옵니다. 이 함수는 또한 상태 필드에서 'a'(Available) 값을 가지고 있는 <code>BookInstance</code> 객체들의 목록도 가져옵니다. 이전 튜토리얼에서 모델 데이터에 접근하는 방법에 대한 더 많은 정보를 찾을 수 있습니다 : <a href="/en-US/docs/Learn/Server-side/Django/Models#Searching_for_records">Django Tutorial Part 3: Using models > Searching for records</a>.</p> + +<p>view 함수의 마지막에선 HTML 페이지를 생성하고 이 페이지를 응답으로서 반환하기 위해 <code>render()</code> 함수를 호출합니다. 이 바로가기(shortcut) 함수는 아주 일반적으로 사용되는 경우들을 간단히 하기 위해 여러 다른 함수들을 포함합니다. <code>render()</code> 함수는 아래 매개 변수들을 허용합니다:</p> + +<ul> + <li><code>HttpRequest</code>인 원본 <code>request</code> 객체.</li> + <li>데이터에 대한 플레이스홀더(placeholder)들을 갖고 있는 HTML 탬플릿.</li> + <li>파이썬 딕셔너리(dictionary)인, 플레이스홀더에 삽입할 데이터를 갖고 있는 <code>context</code>변수.</li> +</ul> + +<p>다음 섹션에서 탬플릿과 context 변수에 대해 더 다루도록 하겠습니다. 이제 탬플릿을 생성하여 사용자들에게 실제로 무언가를 표시해 봅시다!</p> + +<h3 id="탬플릿(Template)">탬플릿(Template)</h3> + +<p>탬플릿은 파일(HTML 페이지 같은)의 구조(structure)나 배치(layout)을 정의하는 텍스트 파일입니다. 탬플릿은 실제 내용물(content)를 나타내기 위해 플레이스홀더(placeholder)들을 사용합니다. 장고는 당신의 어플리케이션 안에서 'templates' 라고 이름지어진 경로 안에서 자동적으로 탬플릿들을 찾을 것입니다. 예를 들어서, 우리가 방금 추가한 색인(index) 뷰 안에서, <code>render()</code> 함수는 <strong>/locallibrary/catalog/templates/ </strong>경로 안에서<strong> <em>index.html </em></strong><em>파일을 찾으려 할 것이고, 파일이 없다면 에러를 표시할 것입니다. 이것은 이전의 변경점들을 저장하고 브라우저에서 <code>127.0.0.1:8000</code>으로 접근해서 확인할 수 있습니다 - 이것은 다른 세부 사항들과 함께 상당히 직관적인 오류 메세지를 표시할 것입니다 : "<code>TemplateDoesNotExist at /catalog/</code>".</em></p> + +<div class="note"> +<p><strong>주의:</strong> 프로젝트의 settings 파일에 기초해서, 장고는 여러 장소에서 탬플릿들을 찾아볼 것입니다. 기본적으로는 설치된 어플리케이션에서 검색합니다. 장고가 어떻게 탬플릿들을 찾는지, 그리고 어떤 탬플릿 양식(format)들을 지원하는지에 관해 여기(<a href="https://docs.djangoproject.com/en/2.0/topics/templates/">Templates</a> (Django docs))에서 찾아볼 수 있습니다.</p> +</div> + +<h4 id="탬플릿_확장(extend)하기">탬플릿 확장(extend)하기</h4> + +<p> 색인(index) 팀플릿은 head 및 body를 위해 표준 HTML 마크업이 필요할 것입니다. 우리가 아직 생성하지 않은 사이트들의 다른 페이지들을 향한 링크를 걸기 위한 탐색(navigation) 섹션도 필요하고요. 그리고 소개 텍스트 및 책 데이터를 표시하는 섹션 또한 필요합니다. 대부분의 HTML과 탐색 구조는 사이트의 모든 페이지에서 동일할 것입니다. 모든 페이지마다 똑같은 코드를 복사하는 대신, 기본 템플릿을 선언하기 위해 장고 탬플릿 언어(Django templating language)를 사용하고, 탬플릿을 확장하여 각각의 페이지 마다 다른 부분들만을 대체(replace)할 수 있습니다.</p> + +<p>아래 코드 조각은 <strong>base_generic.html </strong>파일의 기본 탬플릿 샘플입니다. 이 샘플은 제목, 사이드바를 위한 섹션과 이름이 지정된 <code>block</code> 및 <code>endblock</code> 탬플릿 태그(굵게 표시)가 마크된 주요 내용(main contents)들이 포함된 일반적인 HTML을 포함합니다. 블럭(block)들을 비워두거나, 또는 탬플릿에서 파생된 페이지들을 렌더링할 때 사용할 기본 내용을 포함할 수 있습니다.</p> + +<div class="note"> +<p><strong>주의:</strong> 탬플릿 태그들은 목록을 반복하거나, 변수 값을 기반으로 조건부 연산을 수행하거나, 여타 다른 일들을 할 수 있는 함수입니다. 탬플릿 태그 외에도 탬플릿 구문(syntax)을 사용하면 view에서 탬플릿으로 전달된 변수들을 참조할 수 있고, 탬플릿 필터(filters)를 사용해서 변수의 형식을 지정할 수 있습니다(예를 들어, 문자열을 소문자로 변환).</p> +</div> + +<pre class="brush: html"><!DOCTYPE html> +<html lang="en"> +<head> + <strong>{% block title %}</strong><title>Local Library</title><strong>{% endblock %}</strong> +</head> +<body> + <strong>{% block sidebar %}</strong><!-- insert default navigation text for every page --><strong>{% endblock %}</strong> + <strong>{% block content %}</strong><!-- default content text (typically empty) --><strong>{% endblock %}</strong> +</body> +</html> +</pre> + +<p> 특정한 view를 위해 탬플릿을 정의할 땐, 먼저 <code>extends</code> 탬플릿 태그를 이용하여 기본 탬플릿을 지정합니다 — 아래 코드 샘플을 참조하세요. 그리고 나서 기본 탬플릿에서와 같이 <code>block</code>/<code>endblock</code> 섹션들을 이용해서 대체할 탬플릿의 섹션들을 선언합니다(있을 경우). </p> + +<p>예를 들어, 아래 코드 조각은 extends 탬플릿 태그의 사용 및 content 블럭(block)을 재정의하는 방법을 보여줍니다. 생성된 HTML은 기본 탬플릿에서 정의된 코드와 구조를 포함할 것입니다(<code>title</code> 블럭에서 정의한 기본 내용은 포함하지만, 기본 <code>contents</code> 블럭 대신 새로운 <code>contents</code> 블럭 포함).</p> + +<pre class="brush: html">{% extends "base_generic.html" %} + +{% block content %} + <h1>Local Library Home</h1> + <p>Welcome to LocalLibrary, a website developed by <em>Mozilla Developer Network</em>!</p> +{% endblock %}</pre> + +<h4 id="LocalLibrary_기본_탬플릿">LocalLibrary 기본 탬플릿</h4> + +<p>우리는 아래 코드 조각을 LocalLibrary 웹사이트의 베이스 탬플릿으로 사용할 것입니다. 보시는 바와 같이, 이것은 HTML 코드를 조금 포함하고 <code>title</code>, <code>sidebar</code> 그리고 <code>content</code> 블럭을 정의합니다. 우리는 기본 제목과 모든 책들 및 저자들에 대한 링크를 갖고 있는 기본 사이드바를 갖고 있습니다. 둘 다 미래에 쉽게 변경하기 위해 블럭들 안에 묶여 있습니다.</p> + +<div class="note"> +<p><strong>주의</strong>: 우리는 또한 두 개의 추가적인 탬플릿 태그를 소개합니다: <code>url</code> 과 <code>load static</code>. 이 태그들은 아래 섹션들에서 설명될 것입니다.</p> +</div> + +<p>새로운 파일 <strong>base_generic.html</strong> 을 <strong>/locallibrary/catalog/templates/<em>base_generic.html</em></strong> 경로 안에 생성해서 아래 코드를 파일에 복사 붙여넣기 하세요:</p> + +<pre class="brush: html"><!DOCTYPE html> +<html lang="en"> +<head> + {% block title %}<title>Local Library</title>{% endblock %} + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous"> + <!-- Add additional CSS in static file --> + {% load static %} + <link rel="stylesheet" href="{% static 'css/styles.css' %}"> +</head> +<body> + <div class="container-fluid"> + <div class="row"> + <div class="col-sm-2"> + {% block sidebar %} + <ul class="sidebar-nav"> + <li><a href="{% url 'index' %}">Home</a></li> + <li><a href="">All books</a></li> + <li><a href="">All authors</a></li> + </ul> + {% endblock %} + </div> + <div class="col-sm-10 ">{% block content %}{% endblock %}</div> + </div> + </div> +</body> +</html></pre> + +<p>탬플릿에는 HTML 페이지의 레이아웃과 프리젠테이션을 개선하기 위한 <a href="http://getbootstrap.com/">Bootstrap</a> 의 CSS가 포함되어 있습니다. 부스트스트랩(또는 다른 클라이언트-사이드 웹 프레임워크)를 사용해서 서로 다른 크기의 화면에서도 잘 표시되는 매력적인 페이지를 빠르게 만들 수 있습니다.</p> + +<p>또한 기본 탬플릿은 추가적인 꾸미기(styling)를 제공하는 로컬 css 파일(styles.css)을 참조합니다. <strong>styles.css</strong> 파일을 <strong>/locallibrary/catalog/static/css/</strong> 경로 안에 생성하고 아래 코드를 파일 안에 복사 붙여넣기 하세요:</p> + +<pre class="brush: css">.sidebar-nav { + margin-top: 20px; + padding: 0; + list-style: none; +}</pre> + +<h4 id="색인(index)_탬플릿">색인(index) 탬플릿</h4> + +<p> 새로운 HTML 파일 <strong>index.html</strong> 을 <strong>/locallibrary/catalog/templates/</strong> 경로 안에 생성해서 아래 코드를 파일 안에 복사 붙여넣기 하세요. 보시는 바와 같이 첫째 행에서 우리의 기본 탬플릿을 확장하고, 탬플릿의 기본 <code>content</code> 블럭을 새로운 블럭으로 대체합니다. </p> + +<pre class="brush: html">{% extends "base_generic.html" %} + +{% block content %} + <h1>Local Library Home</h1> + <p>Welcome to LocalLibrary, a website developed by <em>Mozilla Developer Network</em>!</p> + <h2>Dynamic content</h2> + <p>The library has the following record counts:</p> + <ul> + <li><strong>Books:</strong> <strong>\{{ num_books }}</strong></li> + <li><strong>Copies:</strong> <strong>\{{ num_instances }}</strong></li> + <li><strong>Copies available:</strong> <strong>\{{ num_instances_available }}</strong></li> + <li><strong>Authors:</strong> <strong>\{{ num_authors }}</strong></li> + </ul> +{% endblock %}</pre> + +<p>동적 콘텐츠 섹션에서 우리는 우리가 포함하고 싶은 view의 정보를 위한 플레이스홀더(탬플릿 변수)를 선언합니다. 이 변수들은 코드 샘플에서 굵게 표시된 것과 같이 이중 중괄호로(핸들 바)로 묶입니다.</p> + +<div class="note"> +<p><strong>주의:</strong> 탬플릿 변수와 탬플릿 태그(함수)들을 쉽게 알 수 있습니다 - 변수들은 이중 중괄호로 감싸여져 있고(<code>\{{ num_books }}</code>) , 태그들은 퍼센트 기호와 단일 중괄호로 감싸여 있습니다(<code>{% extends "base_generic.html" %}</code>).</p> +</div> + +<p>여기서 주의해야 할 중요한 것은 변수들의 이름은 열쇠(key)들로 정해진다는 것입니다. 이 열쇠(key)들은 우리의 view의 <code>render()</code>함수 안의 <code>context</code> 사전(dictionary)로 전달하는 열쇠입니다(아래를 확인하세요). 변수들은 탬플릿이 렌더링 될 때 그것들과 연관된 값들로 대체될 것입니다. </p> + +<pre class="brush: python">context = { + '<strong>num_books</strong>': num_books, + '<strong>num_instances</strong>': num_instances, + '<strong>num_instances_available</strong>': num_instances_available, + '<strong>num_authors</strong>': num_authors, +} + +return render(request, 'index.html', context=context)</pre> + +<h4 id="Templates_에_정적_파일_참조하기(referencing)">Templates 에 정적 파일 참조하기(referencing)</h4> + +<p>당신의 프로젝트는 자바스크립트, CSS 그리고 이미지를 포함하는 정적 리소스들을 사용할 가능성이 높습니다. 이 파일들의 위치가 알 수 없기 때문에(또는 바뀔 수 있기 때문에), 장고는 <code>STATIC_URL</code> 전역 설정을 기준으로 탬플릿에서의 위치를 특정할 수 있도록 합니다. 기본 뼈대 웹사이트(skeleton website)는 <code>STATIC_URL</code>의 값을 '<code>/static/</code>'으로 설정하지만, 당신은 이것들을 콘텐츠 전달 네트워크(content delivery network)나 다른 곳에서 호스트할 수도 있습니다.</p> + +<p>아래 코드 샘플처럼, 탬플릿 안에서 당신은 먼저 탬플릿 라이브러리를 추가하기 위해 "static"을 지정하는 <code>load</code> 탬플릿 태그를 호출합니다. 그러고 나서 <code>static</code> 탬플릿 태그를 사용할 수 있고 관련 URL을 요구되는 파일에 지정할 수 있습니다.</p> + +<pre class="brush: html"><!-- Add additional CSS in static file --> +{% load static %} +<link rel="stylesheet" href="{% static 'css/styles.css' %}"></pre> + +<p>비슷한 방법으로 이미지를 페이지에 추가할 수 있습니다. 예를 들어:</p> + +<pre class="brush: html">{% load static %} +<img src="{% static 'catalog/images/local_library_model_uml.png' %}" alt="UML diagram" style="width:555px;height:540px;"> +</pre> + +<div class="note"> +<p><strong> 주의</strong>: 위의 샘플은 파일들의 위치를 특정하지만, 장고는 기본적으로 파일을 제공하지 않습니다. 우리는 우리가 웹사이트 뼈대를 생성했을 때(<a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">created the website skeleton</a>) 전역 URL 매퍼(/locallibrary/locallibrary/urls.py)를 수정하여 개발 웹 서버가 파일을 제공하도록 설정했습니다만, 제품화되었을(in production)때도 파일을 제공할 수 있어야 합니다. 이것에 관해 차후에 다루겠습니다.</p> +</div> + +<p> 정적 파일들로 작업하는 것에 대한 더 많은 정보는 장고 문서 안의 <a href="https://docs.djangoproject.com/en/2.0/howto/static-files/">Managing static files</a> 를 참고하세요.</p> + +<h4 id="URL_링크하기(Linking_to_URLs)">URL 링크하기(Linking to URLs)</h4> + +<p>위의 기본 탬플릿은 <code>url</code> 탬플릿 태그를 소개했습니다.</p> + +<pre class="brush: python"><li><a href="{% url 'index' %}">Home</a></li> +</pre> + +<p> 이 태그는 <strong>urls.py</strong>에서 호출된 <code>path()</code> 함수의 이름 및 연관된 view가 그 함수에서 수신받을 모든 인자들을 위한 값들을 허용하고, 리소스에 링크하는 데 사용할 수 있는 URL을 반환합니다 .</p> + +<h4 id="탬플릿을_찾을_수_있는_곳_설정하기">탬플릿을 찾을 수 있는 곳 설정하기</h4> + +<p>탬플릿 폴더 안에서 탬플릿을 찾아볼 수 있도록 장고에게 위치를 가르쳐 주어야 합니다. 그것을 하기 위해서, 아래 코드 샘플에 굵게 표시된 것 처럼 <strong>settings.py</strong> 파일을 수정하여 TEMPLATES 객체에 templates 경로(dir)를 추가하세요.</p> + +<p> </p> + +<pre><code>TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [ +<strong> os.path.join(BASE_DIR, 'templates'), +</strong> ], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +]</code></pre> + +<p> </p> + +<h2 id="어떻게_보일까요">어떻게 보일까요?</h2> + +<p>이 시점에서 우리는 색인(index) 페이지를 나타내기 위해 필요한 모든 요소들을 생성했습니다. 서버를 실행하고 (<code>python3 manage.py runserver</code>) 브라우저에서 <a href="http://127.0.0.1:8000/">http://127.0.0.1:8000/</a>으로 이동하세요. 모든 것이 알맞게 설정되었다면, 당신의 사이트는 아래 스크린샷과 같이 보여야 합니다.</p> + +<p><img alt="Index page for LocalLibrary website" src="https://mdn.mozillademos.org/files/14045/index_page_ok.png" style="border-style: solid; border-width: 1px; display: block; height: 356px; margin: 0px auto; width: 874px;"></p> + +<div class="note"> +<p><strong>주의:</strong> All books와 All authors 링크들에 대한 경로, 뷰 그리고 탬플릿들이 정의되지 않았기 때문에 그 링크들은 작동하지 않을 것입니다. 우리는 단지 <code>base_generic.html</code> 탬플릿 안에 그 링크들을 위한 플레이스홀더(placeholder)들을 삽입했을 뿐입니다.</p> +</div> + +<h2 id="도전_과제">도전 과제</h2> + +<p>모델 쿼리, 뷰 그리고 탬플릿들과의 친밀함을 시험할 수 있는 두 가지 임무가 있습니다. </p> + +<ol> + <li>LocalLibrary 기본 탬플릿(<a href="#The_LocalLibrary_base_template">base template</a>)에는 <code>title</code> 블록이 정의되어 있습니다. 색인 탬플릿(<a href="#The_index_template">index template</a>) 안에 이 블록을 덮어쓰기하고 페이지를 위한 새로운 제목을 만들어 보세요. + + <div class="note"> + <p><strong>힌트:</strong> <a href="#Extending_templates">Extending templates</a> 섹션은 블럭(block)을 생성하고 다른 탬플릿에서 블럭을 확장(extend)하는 방법을 설명합니다.</p> + </div> + </li> + <li>대소문자 구분 없이 특정한 단어를 포함하는 장르와 책들의 개수(count)를 생성하도록 <a href="#View_(function-based)">view</a> 를 수정하고, 결과를 <code>context</code>에 전달해 보세요. 이것은 <code>num_books</code>와 <code>num_instances_available</code>을 생성하고 사용하는 것과 비슷한 방법으로 달성할 수 있습니다. 그리고 나서 이 변수들을 포함시키기 위해 <a href="#The_index_template">index template</a> 를 업데이트 하세요.<br> + </li> +</ol> + +<ul> +</ul> + +<h2 id="요약">요약</h2> + +<p>이제 우리의 사이트를 위한 홈 페이지를 생성했습니다 — 데이터베이스의 여러 레코드들을 표시하고 아직 생성되지 않은 페이지로 링크하는 HTML 페이지 입니다. 그 과정에서 우리는 url 매퍼, view, 모델을 이용한 데이터베이스 쿼리, view에서 탬플릿으로의 정보 전달 그리고 탬플릿의 생성과 확장에 관한 기본적인 정보를 배웠습니다.</p> + +<p>다음 글에서는 이 지식들을 토대로 우리 웹사이트의 나머지 네 개의 페이지들을 생성할 것입니다.</p> + +<h2 id="See_also">See also</h2> + +<ul> + <li><a href="https://docs.djangoproject.com/en/2.0/intro/tutorial03/">Writing your first Django app, part 3: Views and Templates</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.0/topics/http/urls/">URL dispatcher</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.0/topics/http/views/">View functions</a> (DJango docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.0/topics/templates/">Templates</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.0/howto/static-files/">Managing static files</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.0/topics/http/shortcuts/#django.shortcuts.render">Django shortcut functions</a> (Django docs)</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Django/Admin_site", "Learn/Server-side/Django/Generic_views", "Learn/Server-side/Django")}}</p> + +<p> </p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Server-side/Django/Introduction">Django introduction</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/development_environment">Setting up a Django development environment</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Django Tutorial: The Local Library website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django Tutorial Part 2: Creating a skeleton website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Models">Django Tutorial Part 3: Using models</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Admin_site">Django Tutorial Part 4: Django admin site</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django Tutorial Part 5: Creating our home page</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Generic_views">Django Tutorial Part 6: Generic list and detail views</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Sessions">Django Tutorial Part 7: Sessions framework</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Authentication">Django Tutorial Part 8: User authentication and permissions</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Forms">Django Tutorial Part 9: Working with forms</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Testing">Django Tutorial Part 10: Testing a Django web application</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Django Tutorial Part 11: Deploying Django to production</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/web_application_security">Django web application security</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></li> +</ul> + +<p> </p> diff --git a/files/ko/learn/server-side/django/index.html b/files/ko/learn/server-side/django/index.html new file mode 100644 index 0000000000..2545082955 --- /dev/null +++ b/files/ko/learn/server-side/django/index.html @@ -0,0 +1,65 @@ +--- +title: Django 웹 프레임워크 (파이썬) +slug: Learn/Server-side/Django +tags: + - 서버 사이드 프로그래밍 + - 장고 + - 초보자 + - 파이썬 +translation_of: Learn/Server-side/Django +--- +<div>{{LearnSidebar}}</div> + +<p>Django는 파이썬으로 구성된, 인기 많고 완벽한 기능을 갖춘 서버-사이드 웹 프레임워크입니다. 이 모듈은 Django가 웹 서버 프레임워크 중 가장 유명한 이유, 개발환경을 설정하는 방법, 그리고 이를 통해 자신만의 웹 애플리케이션을 만드는 방법을 알려줍니다. </p> + +<h2 id="전제조건">전제조건</h2> + +<p>이 모듈을 시작하기에 앞서, 당신이 Django에 대해 미리 알 필요는 전혀 없습니다. 하지만 <a href="/ko/docs/Learn/Server-side/First_steps">Server-side website programming first steps</a> 모듈을 보면서 과연 서버-사이드 웹 프로그래밍과 웹 프레임워크가 무엇인가에 대해서는 이해 할 필요가 있습니다.</p> + +<p>프로그래밍 개념 그리고 <a href="/ko/docs/Glossary/Python">Python</a>에 대한 일반적인 지식을 공부하는 것은 권장합니다. 하지만 이것이 Django의 핵심 개념을 이해하는데 반드시 필요한 것은 아닙니다.</p> + +<div class="note"> +<p><strong>노트</strong>: Python은 초보자가 읽고 이해할 수 있는 가장 쉬운 프로그래밍 언어 중 하나 입니다. 즉, 만약 당신이 이 모듈을 더 깊이 이해하고 싶다면, 인터넷에서 많은 무료 서적과 자습서들을 이용할 수 있습니다. ( 초보 프로그래머들은 python.org wiki 에서 <a href="https://wiki.python.org/moin/BeginnersGuide/NonProgrammers">Python for Non Programmers</a> 페이지를 확인해도 좋습니다.).</p> +</div> + +<h2 id="가이드">가이드</h2> + +<dl> + <dt><a href="/ko/docs/Learn/Server-side/Django/Introduction">Django 소개</a></dt> + <dd>이 문서에서는 "Django란 무엇인가?" 라는 물음에 답을 합니다. 그리고 이 웹 프레임워크를 특별하게 만드는 요소에 대해 대략적으로 살펴볼 것입니다. 우리는 여기서 Django의 주요 특징들 (자세히 설명할 시간은 없는 심화된 기능들 포함) 을 훑어볼 것입니다. 또한 Django 애플리케이션의 주요 구성 요소들 중 일부를 보여줍니다. 따라서 당신이 Django 애플리케이션을 설정하고 시작하기 전에, 우리는 Django가 무슨 일을 해 줄 수 있는지에 대해 알려줄 것입니다. </dd> + <dt><a href="/ko/docs/Learn/Server-side/Django/development_environment">Django 개발 환경 설정</a></dt> + <dd>이제 Django가 무엇인지 알았으므로 Windows, Linux (Ubuntu) 및 Mac OS X에서 Django 개발 환경을 설정하고 테스트하는 방법을 살펴봅시다. 이 문서에서는 당신이 어떠한 운영 체제를 사용하든지 상관없습니다. 우리는 당신이 Django로 앱 개발을 시작하기 전에 필요한 것을 마땅히 알려줘야 합니다. </dd> + <dt><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Django Tutorial: The Local Library website</a></dt> + <dd>이 (실용적) 튜토리얼의 첫번째 문서에서는 앞으로 무엇을 배울지 알아봅니다. - 우리가 후속 문서에서 계속 작업하고 개발해 나갈 "로컬 저장소" 의 예제 웹사이트를 살펴봅니다.</dd> + <dt><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django Tutorial Part 2: Creating a skeleton website</a></dt> + <dd>이 수업에서는 웹사이트의 기본인 "뼈대"를 만드는 방법을 살펴봅니다. 그런 다음 사이트별로 settings, urls, models, views, templates 을 사용하여 채워 넣을 것입니다.</dd> + <dt><a href="/en-US/docs/Learn/Server-side/Django/Models">Django Tutorial Part 3: Using models</a></dt> + <dd>이 수업에서는 로컬 저장소 웹사이트에서 모델을 저장하는 방법에 대해 알아봅니다. 모델이란 웹 앱의 자료구조를 나타내며, Django의 데이터 베이스에 데이터를 저장할 수 있도록 해줍니다. 여기서는 모델이 무엇인지, 어떻게 선언하는지, 그리고 몇몇 중요한 필드 타입도 살펴볼 것입니다. 그리고 모델 데이터에 접근하는 몇가지 주요 방법도 간단하게 알아봅니다. </dd> + <dt><a href="/en-US/docs/Learn/Server-side/Django/Admin_site">Django Tutorial Part 4: Django admin site</a></dt> + <dd>앞에서 로컬라이브러리 웹사이트의 모델을 생성했다면, 이제는 Django 관리자 사이트를 사용해서 "실제" 책 데이터를 추가할 차례입니다. 먼저 관리자 사이트에 모델에 등록하는 방법을 보여줄 것입니다. 그 다음에 로그인 하고 데이터를 생성하는 방법도 배울 것입니다. 마지막 순서에서는 관리자 사이트의 PT를 향상시키는 더 많은 방법도 알아볼 것입니다. </dd> + <dt><a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django Tutorial Part 5: Creating our home page</a></dt> + <dd>이제 우리는 처음으로 완성된 페이지(홈페이지 개념으로 모델 종류를 기록하고 사이드바나 다른 페이지의 링크들이 있음)를 표시하기 위한 코드를 입력할 준비가 되었습니다. 이 방법을 통해 기본적인 URL 맵이나 뷰를 작성하고, 데이터베이스에 기록하고, 템플릿을 사용하는 실용적인 경험을 얻을 것입니다. </dd> + <dt><a href="/en-US/docs/Learn/Server-side/Django/Generic_views">Django Tutorial Part 6: Generic list and detail views</a></dt> + <dd>이 수업에서는 우리가 만든 local library의 웹사이트를 확장해 볼 것입니다. 목록, 책이나 저자 정보를 담은 자세한 페이지들을 추가할 것입니다. 여기서는 일반적인 클래스 기반의 view를 배우고 보통 상황에서 어떻게 코드의 양을 줄일 수 있는지 살펴볼 것입니다. 우리는 또한 URL 핸들링에 대해 정말 자세히 들어가서, 기본적인 패턴 매칭을 어떻게 해야 하는지도 볼 것입니다. </dd> + <dt><a href="/en-US/docs/Learn/Server-side/Django/Sessions">Django Tutorial Part 7: Sessions framework</a></dt> + <dd>여기서는 우리가 만든 로컬 라이브러리의 웹사이트에 '세션 기반 방문자 수 계산기' 를 홈페이지에 추가할 것입니다. 이것은 비교적 간단한 예제입니다. 하지만 귀하는 이 예제를 통해, 세션 프레임워크를 사용해서 어떻게 사이트에 방문하는 이름없는 사용자들의 반복적인 행동을 볼 수 있는지 (그 방법을) 알 수 있습니다. </dd> + <dt><a href="/en-US/docs/Learn/Server-side/Django/Authentication">Django Tutorial Part 8: User authentication and permissions</a></dt> + <dd>이 수업에서는 유저들에게 그들의 계정으로 웹사이트에 로그인 하게 하는 방법에 대해 배웁니다. 그리고 로그인 상태에 따라 그들이 보고 작성할 수 있는 범위를 통제하는 방법, 그들에게 허가를 내주는 방법을 배웁니다. 우리는 연습을 위해서 로컬 라이브러리 웹사이트를 확장해 볼 것입니다. 로그인 및 로그아웃 페이지를 추가하고, 대출 도서를 보여주는 페이지를 사용자용, 관리자용 각각 따로 만들어 볼 것입니다. </dd> + <dt><a href="/en-US/docs/Learn/Server-side/Django/Forms">Django Tutorial Part 9: Working with forms</a></dt> + <dd>여기서는 Django에서 <a href="/en-US/docs/Web/Guide/HTML/Forms">HTML Forms</a>을 어떻게 사용하는 살펴볼 것입니다. HTML은 특히 모델을 생성하고, 갱신하고, 지우는 등의 폼을 작성하는 가장 쉬운 방법입니다. 이번 연습에서는 로컬 라이브러리의 웹사이트를 확장하는 것도 포함되어 있습니다. 여기서 우리는 도서관 사서들이 (관리자 어플리케이션 보다는) 우리가 작성한 폼을 이용해서 책을 고치고, 생성하고, 업데이트하고 정보를 삭제할 수 있도록 웹사이트를 확장해 볼 것입니다. </dd> + <dt><a href="/en-US/docs/Learn/Server-side/Django/Testing">Django Tutorial Part 10: Testing a Django web application</a></dt> + <dd>웹사이트가 확장되어감에 따라 일일이 확인하기가 점점 어려워질 것입니다. 테스트해야할 요소 자체가 많아질 뿐만 아니라 요소간의 상호관계도 복잡해지면서 작은 요소의 변화가 다른 큰 요소들에까지 영향을 미치게됩니다. 이런 문제에 대한 걱정을 덜어줄 수 있는 방법은 자동 테스트 코드를 작성하는 것입니다. 자동 테스트 코드는 소스에 변화가 생길때마다 작동하는 코드입니다. 이번 강좌에서는 성능이 우수하면서도 작성이 간단한 Django의 테스트 프레임워크로 어떻게 당신의 웹사이트를 단위 테스트할수 있는지 알아봅니다.</dd> + <dt><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Django Tutorial Part 11: Deploying Django to production</a></dt> + <dd>이제 당신은 훌륭한 로컬저장소 웹사이트를 만들었으니, 로컬저장소가 아닌 공개 서버에 업로드 함으로써 인터넷을 통해 관리자와 사용자들이 접근할 수 있도록 하고싶을 겁니다. 이 수업에서는 호스트 업체를 찾고 웹사이트를 등록하는 방법과 사이트에 상품가치를 부여하는 방법을 알아봅니다.</dd> + <dt><a href="/en-US/docs/Learn/Server-side/Django/web_application_security">Django web application security</a></dt> + <dd>사용자의 데이터를 보호하는 것은 웹사이트 디자인에서 중요한 부분입니다. 이전에 <a href="https://developer.mozilla.org/en-US/docs/Web/Security">Web security</a> 수업에서 일반적인 보안 위협들에 대해 알아보았습니다. 이번 항목에서는 Django에 내장된 보호 시스템이 이런 위협을 어떻게 처리하는지 실질적인 예시에 대해 살펴봅니다. </dd> +</dl> + +<h2 id="평가">평가</h2> + +<p>밑에 제시되어있는 평가는 위에 설명 된 대로, 장고(Django)를 사용하여 웹 사이트를 만드는 방법에 대한 이해도를 테스트합니다.</p> + +<dl> + <dt><a href="/ko/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django 미니 블로그</a></dt> + <dd>이 평가에서, 귀하는 여기서 배운 지식을 활용해서 자신만의 블로그를 만들 수 있습니다. </dd> +</dl> diff --git a/files/ko/learn/server-side/django/introduction/index.html b/files/ko/learn/server-side/django/introduction/index.html new file mode 100644 index 0000000000..f8034af90e --- /dev/null +++ b/files/ko/learn/server-side/django/introduction/index.html @@ -0,0 +1,256 @@ +--- +title: Django 소개 +slug: Learn/Server-side/Django/Introduction +tags: + - 장고 +translation_of: Learn/Server-side/Django/Introduction +--- +<p>{{LearnSidebar}}</p> + +<div>{{NextMenu("Learn/Server-side/Django/development_environment", "Learn/Server-side/Django")}}</div> + +<p class="summary">Django의 첫번째 문서에서는 "Django가 뭐지?"라는 질문에 답해보고, Django 웹 프레임워크의 특별한 부분에 대해 전반적으로 살펴봅니다. 우리가 이 수업에서 자세히 다루지는 않을 고급 기능들까지 포함하여 간단하게 전반적인 부분을 살펴 볼겁니다. 또한, Django 애플리케이션을 구성하는 중요한 요소도 살펴보겠습니다. (물론 지금 시점에서는 테스트를 할 개발환경을 가지고 있지 않겠지만요.)</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">요구 사항</th> + <td>기본적인 컴퓨터 지식. <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/First_steps">server-side website 프로그래밍</a>에 대한 전반적인 이해, 그리고 웹사이트의 <a href="/en-US/docs/Learn/Server-side/First_steps/Client-Server_overview">client-server interactions</a> 의 매커니즘에 대한 특정한 지식.</td> + </tr> + <tr> + <th scope="row">목표</th> + <td> + <p>Django란 무엇인지, 어떤 기능이 있는지, Django 어플리케이션의 주요 구성요소는 어떤것들인지에 대해 익숙해지기</p> + </td> + </tr> + </tbody> +</table> + +<h2 id="Django란">Django란?</h2> + +<p>Djano란 보안이 우수하고 유지보수가 편리한 웹사이트를 신속하게 개발하는 하도록 도움을 주는 파이썬 웹 프레임워크입니다. 훌륭한 개발자에 의해 만들어진 이 프레임워크는, 웹 개발을 하는데 많은 도움을 주기 때문에 새롭게 웹 개발을 시작할 필요없이 그저 프레임워크를 활용하여 앱 개발에만 집중할 수 있게되죠. 무료 오픈소스인데다가, 활발한 커뮤니티들이 있고, 좋은 참고자료와 무료 및 유료 지원을 하는 옵션들이 제공됩니다.</p> + +<p>Django는 다음과 같은 소프트웨어를 개발하는데 도움을 줍니다.</p> + +<dl> + <dt>Complete(완결성 있는)</dt> + <dd>Django는 "Batteries included" 의 철학을 기반으로 개발자들이 개발하고 싶은 거의 모든것을 개발하는데 도움을 줍니다. 개발자들이 원하는 것은 모두 하나의 "결과물"의 일부일 것이기 때문에 도달하고자 하는 목표지점은 같으며 이 덕분에 일관된 디자인 룰을 적용하여 <a href="https://docs.djangoproject.com/en/2.2/">광범위한 최신 문서</a>를 제공합니다.</dd> + <dt>Versatile(다용도의)</dt> + <dd>Django는 문서관리시스템과 Wiki부터 SNS, 뉴스에 이르기까지 다양한 종류의 웹 사이트를 빌드하는데 사용할 수 있고 사용되어 왔습니다. 또한 어떠한 클라이언트측 프레임워크와도 협업할 수 있고, 대부분의 형식(HTML, RSS 피드, JSON, XML 등)으로 컨텐츠를 전송할 수 있습니다. 당신이 보고 있는 이 사이트도 Django 기반입니다!<br> + <br> + 내부적으로 Django는 당신이 원하는 대부분의 기능들(몇몇 유명한 데이터베이스들, 템플릿 엔진 등)을 제공하지만, 필요하다면 다른 컴포넌트들을 사용하기 위해 확장될 수 있습니다. </dd> + <dt>Secure(안전한)</dt> + <dd>Django 는 개발자들이 웹사이트를 개발할 때 실수하기 쉽지만 고려해야하는 보안 문제에 대해서 많은 도움을 줍니다. 예를 들면, 장고는 유저의 계정과 비밀번호를 관리하는 안전한 방법을 제공합니다. 이 예에서 발생할 수 있는 개발자들의 실수로 세션의 정보를 보안에 취약한 위치에 있는 쿠키(해결책은 쿠키는 그저 key값을 가지도록 하는 반면 실제 데이터는 데이터 베이스에 저장하도록 하는 것입니다)에 넣는 실수를 하는 것입니다. 또 달리 쉽게할 수 있는 실수는 비밀번호를 hash를 통하지 않고 그대로 변형없이 저장하는 것이 있습니다.<br> + <br> + <em>비밀번호에 사용되는 hash 는 <a href="https://en.wikipedia.org/wiki/Cryptographic_hash_function">cryptographic hash function</a>에 의해 생성된 고정된 길이의 값을 가집니다. Django는 이렇게 변형되어 입력된 비밀번호가 유효한지 hash 함수를 통해 확인할 수 있습니다. 하지만 "단방향" 적인 함수의 특성상, 저장된 hash 값을 웹을 공격하는 사람들이 알아낸다고 하더라도 원본 비밀번호는 알아낼 수 없습니다.</em><br> + <br> + Django 는 SQL 인젝션, 크로스사이트 스크립팅, 크로스사이트 요청 위조 그리고 클릭 하이젝킹 (이러한 공격 방법에 대한 상세 정보는 <a href="/en-US/docs/Learn/Server-side/First_steps/Website_security">Website security</a>에서 볼 수 있습니다)과 같은 보안 취약점을 보완할 방법 기본적으로 제공합니다.</dd> + <dt>Scalable(확장성 있는)</dt> + <dd>Django는 컴포넌트 기반의 “<a href="https://en.wikipedia.org/wiki/Shared_nothing_architecture">shared-nothing</a>” 아키텍쳐(각각의 아키텍쳐가 독립적이어서 필요하다면 교체 및 변경할 수 있는)를 사용합니다. 각 부분이 분명하게 분리되면 어떤 레벨에서든(예를 들면 캐싱 서버, 데이터베이스 서버, 혹은 어플리케이션 서버) 하드웨어를 추가해서 발생하는 늘어난 트래픽에 대응해 크기를 변경할 수 있게 됩니다. 사용자가 가장 많은 몇몇 사이트는 요구사항에 맞춰서 Django의 크기를 성공적으로 변경했습니다. (예를들면 Instagram, Disqus 등)</dd> + <dt>Maintainable(유지보수가 쉬운)</dt> + <dd>Django 코드는 유지보수가 쉽고 재사용하기 좋게끔 하는 디자인 원칙들과 패턴들을 이용하여 작성됩니다. 특히 Don't Repeat Yourself (DRY) 원칙을 적용해서 불필요한 중복이 없고 많은 양의 코드를 줄였습니다. 또한 Django는 관련된 기능들을 재사용 가능한 "applications"로 그룹화했고, 더 낮은 레벨에서 관련된 코드들을 모듈로 만들었습니다. (<a href="/en-US/Apps/Fundamentals/Modern_web_app_architecture/MVC_architecture">Model View Controller (MVC)</a> 패턴과 유사합니다).</dd> + <dt>Portable(포터블한)</dt> + <dd>장고는 파이썬으로 작성되어 있으며, 파이썬은 많은 플랫폼에서 작동합니다. 그것은 특정한 서버 플랫폼에 얽매이지 않는다는 것을 의미하며, 리눅스, 윈도우 그리고 맥 OS X 등등 다양한 운영체제에서 작동할 수 있다는 뜻입니다. 나아가, 장고는 많은 웹 호스팅 공급자들에 의해서 지원되고 있습니다. 그들은 장고 사이트의 호스팅과 관련해서 특정한 인프라와 문서를 제공합니다. </dd> +</dl> + +<h2 id="탄생_배경은_어떻게_되나요">탄생 배경은 어떻게 되나요?</h2> + +<p>장고는 신문 웹사이트를 제작 및 관리하던 어떤 웹 팀에 의해 2003년에서 2005년 사이에 처음으로 개발이 시작되었습니다. 여러 사이트들을 만들면서 웹 팀은 많은 공통 코드와 설계 패턴을 뽑아내어 재사용하였습니다. 이 공통 코드는 일반 웹 개발 프레임워크로 발전했습니다. 그리고 2005년 7월 "장고" 프로젝트로서 오픈소스화 되었죠.. </p> + +<p>장고는 2008년 9월 첫 번째 주요 릴리즈(1.0)에서부터 2017년의 최근 버전(2.0)까지 성장하고 발전했습니다. 장고는 각각의 버전에서 기능을 추가하고 버그를 수정했습니다. 새로운 유형의 데이터베이스, 탬플릿 엔진들 그리고 캐싱에 대한 지원에서부터 일반 보기 함수와 클래스들의 추가까지요(이를 통해 여러 프로그래밍 작업을 위해 개발자들이 작성해야 할 코드를 줄여줍니다). </p> + +<div class="note"> +<p><strong>Note</strong>: 장고를 더 좋게 만들기 위해 어떤 작업이 이루어지고 있는지, 최근 버전에서 어떤 변경이 있었는지 확인하려면 장고 웹사이트의 <span style="line-height: 1.5;"><a href="https://docs.djangoproject.com/en/1.10/releases/">release notes</a> 를 살펴보세요.</span></p> +</div> + +<p>장고는 수많은 사용자와 기여자가 있는 협력적이고 번성하는 프로젝트입니다. 여전히 몇 가지 장고만의 특징이 있지만, 장고는 모든 유형의 웹사이트를 개발할 수 있는 다용도적인 웹 프레임워크로 발전했습니다.</p> + +<h2 id="Django의_인기는_어떤가요">Django의 인기는 어떤가요?</h2> + +<p>사실 서버 측 프레임워크의 인기에 대해 쉽고 확정적인 측정값은 없습니다(다만 <a href="http://hotframeworks.com/">Hot Frameworks</a> 와 같은 사이트는 각 플랫폼에 대해 GitHub 프로젝트와 StackOverflow 질문의 숫자를 세는 방법으로 인기에 대해 접근하려고 합니다). 장고가 인기없는 플랫폼의 문제를 피할 수 있을 만큼 "충분히 인기있는지"가 더 좋은 질문입니다. 장고가 계속 발전하나요? 도움이 필요할 때 받을 수 있나요? 장고를 배우면 돈을 받고 일할 기회가 생기나요?</p> + +<p>장고를 사용하는 상위 사이트의 숫자, 장고 코드베이스에 기여하는 사람들의 숫자, 그리고 급여가 지불되거나 지불되지 않거나에 상관없이 지원을 제공하는 사람들의 숫자에 근거해서, 맞습니다. 장고는 인기있는 프레임워크 입니다!</p> + +<p>장고를 사용하는 상위 사이트는 다음을 포함합니다 : Disqus, Instagram, Knight Foundation, MacArthur Foundation, Mozilla, National Geographic, Open Knowledge Foundation, Pinterest, and Open Stack (출처: <a href="https://www.djangoproject.com/">Django home page</a>).</p> + +<h2 id="Django는_독선적인가요">Django는 독선적인가요?</h2> + +<p>많은 웹 프레임웍들이 흔히 스스로를 "독선적(opinionated)"이라거나 "관용적(unopinionated)"이라고 표현합니다.</p> + +<p>독선적인 프레임웍들은 어떤 특정 작업을 다루는 "올바른 방법"에 대한 분명한 의견을 가지고 있습니다. 그것들은 대체로 특정 도메인(특정 타입의 문제를 해결하는)내에서 빠른 개발방법을 제시합니다. 어떤 작업에 대한 올바른 방법이란 보통 잘 알려져있고 문서화가 잘되어있기 때문입니다. 하지만 그것들은 주요 도메인을 벗어난 문제에 대해서는 그리 유연하지 못한 해결책을 제시할 수 있습니다. 또한 이용할수 있는 접근법이나 선택가능한 구성요소가 그리 많지 않을것입니다. </p> + +<p>반면에, 관용적인 프레임웍들은, 구성요소를 한데 붙여서 해결해야 한다거나 심지어 어떤 컴퍼넌트를 써야한다는 '올바른 방법'에 대한 제약이 거의 없다시피 합니다. 그것들은 개발자들이 특정 작업을 완수하는데에 가장 적절한 도구들을 이용하기 쉽게 만들어줍니다. 비록 당신 스스로가 그 컴퍼넌트들을 찾아야 한다는 수고는 해야하긴 하지만 말이죠.</p> + +<p>Django는 "다소 독선적" 입니다. 그럼으로써 "양쪽 세계의 최선"의 결과를 전달합니다. Django는 대부분의 웹 개발 작업을 다루는 컴퍼넌트 세트와 그 세트를 이용하는 한, 두가지의 인기있는 방법을 제공합니다. 하지만 Django의 비결합 구조 (decoupled architecture) 덕분에 당신은 꽤 많은 옵션들중에서 다른 방법을 선택하거나 원한다면 완전히 새로운 방법을 만들어 낼 수도 있습니다.</p> + +<h2 id="Django_코드는_어떻게_생겼나요">Django 코드는 어떻게 생겼나요?</h2> + +<p>전형적인 데이터 기반 웹 사이트에서 웹 어플리케이션은 웹 브라우저(또는 다른 클라이언트)로부터 HTTP 요청(Request)을 기다립니다. 요청을 받으면, 웹 어플리케이션은 URL과 <code>POST</code> 데이터 또는 <code>GET</code> 데이터의 정보에 기반하여 요구사항을 알아냅니다. 그 다음 무엇이 필요한 지에 따라, 데이터베이스로부터 정보를 읽거나 쓰고, 또는 필요한 다른 작업들을 수행할 것입니다. 그 다음 웹 어플리케이션은 웹 브라우저에 응답(Response)을 반환하는데, 주로 동적인 HTML 페이지를 생성하면서 응답합니다.</p> + +<p>Django 웹 어플리케이션은 전형적으로 아래와 같이 분류된 파일들에 대해 일련의 단계를 수행하는 코드로 구성되어 있습니다:</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/13931/basic-django.png" style="border-style: solid; border-width: 1px; display: block; margin: 0px auto;"></p> + +<ul> + <li><strong>URLs: </strong>단일 함수를 통해 모든 URL 요청을 처리하는 것이 가능하지만, 분리된 뷰 함수를 작성하는 것이 각각의 리소스를 유지보수하기 훨씬 쉽습니다. URL mapper는 요청 URL을 기준으로 HTTP 요청을 적절한 뷰(view)로 보내주기 위해 사용됩니다. 또한 URL mapper는 URL에 나타나는 특정한 문자열이나 숫자의 패턴을 일치시켜 데이터로서 뷰 함수에 전달할 수 있습니다.</li> + <li><strong>View:</strong> 뷰는 HTTP 요청을 수신하고 HTTP 응답을 반환하는 요청 처리 함수입니다. 뷰는 Model을 통해 요청을 충족시키는데 필요한 데이터에 접근합니다. 그리고 탬플릿에게 응답의 서식 설정을 맡깁니다.</li> + <li><strong>Models:</strong> 모델은 응용프로그램의 데이터 구조를 정의하고 데이터베이스의 기록을 관리(추가, 수정, 삭제)하고 쿼리하는 방법을 제공하는 파이썬 객체입니다.</li> + <li><strong>Templates: </strong>탬플릿은 파일의 구조나 레이아웃을 정의하고(예: HTML 페이지), 실제 내용을 보여주는 데 사용되는 플레이스홀더를 가진 텍스트 파일입니다. 뷰는 HTML 탬플릿을 이용하여 동적으로 HTML 페이지를 만들고 모델에서 가져온 데이터로 채웁니다. 탬플릿으로 모든 파일의 구조를 정의할 수 있습니다.탬플릿이 꼭 HTML 타입일 필요는 없습니다!</li> +</ul> + +<div class="note"> +<p><strong>Note</strong>: 장고는 이 구조를 "모델 뷰 템플릿(Model View Template)(MVT)" 아키텍처라고 부릅니다. 이것은 더 익숙한 <a href="/en-US/docs/Web/Apps/Fundamentals/Modern_web_app_architecture/MVC_architecture">Model View Controller</a> 아키텍처와 많은 유사점을 가지고 있습니다.</p> +</div> + +<ul> +</ul> + +<p>아래 부문들은 장고 앱의 주요 부분들이 어떻게 보일지에 대한 단서를 보여줄 것입니다 (우리는 개발 환경을 설치한 이후에 세부적인 디테일에 대해 다룰겁니다).</p> + +<h3 id="요청을_알맞은_뷰로_전달_urls.py">요청을 알맞은 뷰로 전달 (urls.py)</h3> + +<p>URL mapper는 보통 <strong>urls.py</strong>라는 이름의 파일에 저장되어 있습니다. 아래 예시에서 <code>urlpatterns</code> 맵퍼는 경로들(특정 URL 패턴들)과 해당하는 뷰 함수에 대한 맵핑 목록들을 정의합니다. 만약 지정된 URL 패턴과 일치하는 HTTP 요청이 수신된다면 관련된 view 함수가 요청을 전달합니다.</p> + +<pre class="notranslate"><code>urlpatterns = [ + path('admin/', admin.site.urls), + path('book/<int:id>/', views.book_detail, name='book_detail'), + path('catalog/', include('catalog.urls')), + re_path(r'^([0-9]+)/$', views.best), +]</code></pre> + +<p><code>urlpatterns</code> 객체는 <code>path()</code>함수와 <code>re_path()</code><span> 함수를 항목으로 가지는 리스트입니다 (파이썬 리스트는 대괄호를 사용하여 구분되며, 항목은 쉼표로 분리되고 선택적으로 후행 쉼표가 있을 수 있습니다. 예시: [item1, item2, item3, ]).</span></p> + +<p><span>두 메소드의 첫 번째 인수는 일치시킬 경로(패턴)입니다. </span><code>path()</code><span> 메소드는 꺾쇠 괄호(<, >)를 사용해서 인수를 정의합니다. 이 인수는 URL의 한 부분으로, 명명된 인수로 수집되어 뷰 함수로 보내집니다. </span><code>re_path()</code><span> 함수는 정규식이라는 유연한 패턴 매칭 접근을 사용합니다. 이것에 대해서는 나중에 다루도록 하겠습니다!</span></p> + +<p>두 번째 인수는 패턴이 일치할 때 호출되는 다른 함수입니다. <code>views.book_detail</code>은 이 함수가 <code>book_detail()</code>이며 <code>views</code> 모듈 안에서 찾을 수 있다는 것을 나타냅니다 (즉, <code>views.py</code>라는 파일 안에서요).</p> + +<h3 id="요청_처리하기_views.py">요청 처리하기 (views.py)</h3> + +<p>뷰들은 웹 클라이언트로부터 HTTP 요청을 수신하고 HTTP 응답을 되돌려주는 웹 어플리케이션의 심장입니다. 그 사이에 그들은 데이터베이스에 접근하고 템플릿을 렌더링하기 위해 프레임워크읟 다른 자원들을 정리합니다.</p> + +<p>아래 예시는 이전 예시의 URL mapper가 불러올 수 있는 최소 뷰 함수 <code>index()</code>를 보여줍니다. 다른 모든 뷰 함수처럼 이 함수도 <code>HttpRequest</code> 객체를 인자(<code>request</code>)로 받고 <code>HttpResponse</code> 객체를 반환합니다. 이 예시에서는 요청에 관해서는 아무것도 하지 않고, 단순히 하드코딩된 문자열을 반환합니다. 요청에 관련해서는 이후 글에서 더 자세하게 다루겠습니다.</p> + +<pre class="brush: python notranslate">## filename: views.py (Django view functions) + +from django.http import HttpResponse + +def index(request): + # Get an HttpRequest - the request parameter + # perform operations using information from the request. + # Return HttpResponse + return HttpResponse('Hello from Django!') +</pre> + +<div class="note"> +<p><strong>Note</strong>: 파이썬에 관하여:</p> + +<ul> + <li><a href="https://docs.python.org/3/tutorial/modules.html">Python modules</a>은 우리가 코드에 쓰고 싶을지도 모르며 분리된 파일로 저장되어 있는 함수의 "라이브러리" 입니다.</li> + <li><code>from django.http import HttpResponse</code>와 같은 방법으로 <code>django.http</code> 모듈에서 <code>HttpResponse</code> 객체만 가져와서 뷰에서 사용할 수 있습니다. 모듈에서 여럿, 아니면 전체 모듈을 임포트할 수 있는 몇 가지 방법이 있습니다.</li> + <li>함수들은 위에 보여진 것과 같이<code>def</code> 키워드로 정의됩니다. 함수의 이름 뒤 괄호 안에 는 명명된 인자들이 나열되어 있습니다. 전체 줄은 콜론으로 끝납니다. 그 아랫 줄이 모두 <strong>들여쓰기 되어있다는 것</strong>에 유의하세요. 들여쓰기는 코드 행이 특정한 블록 안에 있다는 것을 나타내기 때문에 중요합니다(필수적인 들여쓰기는 파이썬의 주요 기능이며, 파이썬 코드가 읽기 쉬운 이유 중 하나이기도 합니다).</li> +</ul> +</div> + +<ul> +</ul> + +<p>뷰들은 보통 <strong>views.py</strong>.라는 파일 안에 저장되어 있습니다.</p> + +<h3 id="데이터_모델_정의하기_models.py">데이터 모델 정의하기 (models.py)</h3> + +<p>장고 웹 어플리케이션은 모델(models)이라는 파이썬 객체를 통해 데이터를 관리하고 쿼리합니다. 모델은 필드 타입과 그들의 최대 크기, 기본 값들, 선택 목록 옵션, 문서의 도움말 텍스트, 폼(form)을 위한 labe text등을 포함하여 저장된 데이터의 구조를 정의합니다. 모델의 정의는 기본 데이터베이스와 별개입니다. 본인의 프로젝트 설정의 일부로써 여러 모델 중 하나를 선택할 수 있습니다. 본인이 사용할 데이터베이스를 정했다면, 그것에 직접적으로 접근할 필요가 없습니다. 그저 모델 구조와 다른 코드들을 작성하면, 장고가 당신과 데이터베이스가 소통하는 데 필요한 모든 더러운 작업들을 처리합니다.</p> + +<p>아래 코드는 <code>Team</code> 객체를 위한 아주 간단한 장고 모델을 보여줍니다. <code>Team</code> 객체는 장고 클래스<code>models.Model</code>에서 파생되었습니다. 이 객체는 팀 이름과 팀 레벨을 캐릭터 필드로 정의하고 각각의 기록에 저장될 최대 캐릭터 숫자를 정합니다. <code>team_level</code>은 랜덤으로 값이 선정되기 때문에, 우리는 이를 choice 필드로 정의하며, choices들 간에 선택된 값이 보여지고 디폴트 값에 따른 데이터가 저장되도록 합니다. </p> + +<pre class="brush: python notranslate"># filename: models.py + +from django.db import models + +class Team(models.Model): + team_name = models.CharField(max_length=40) + + TEAM_LEVELS = ( + ('U09', 'Under 09s'), + ('U10', 'Under 10s'), + ('U11', 'Under 11s'), + ... #list other team levels + ) + team_level = models.CharField(max_length=3, choices=TEAM_LEVELS, default='U11') +</pre> + +<div class="note"> +<p><strong>참고 : 파이썬에 대해</strong></p> + +<p>파이썬은 코드를 객체로 구성하는 프로그래밍 스타일인 "객체 지향 프로그래밍"을 지원합니다. 여기에는 관련 데이터 및 해당 데이터를 조작하기위한 함수가 포함됩니다. 객체는 다른 객체로부터 상속, 확장, 파생할 수 있어 관련 객체 간의 공통 동작을 공유 할 수 있습니다. 파이썬에서는 키워드 클래스를 사용하여 객체의 "청사진"을 정의합니다. 클래스의 모델을 기반으로 객체 유형의 여러 특정 인스턴스를 만들 수 있습니다.</p> + +<p>예를 들어 여기 Model 클래스에서 파생된 Team 클래스가 있습니다. 이는 모델이며 모델의 모든 방법을 포함할 것이지만 고유한 기능도 제공 할 수 있습니다. 이 모델에서는 데이터베이스가 데이터를 저장하는데 필요한 필드를 정의하여 특정 이름을 지정합니다. 장고는 필드 이름을 포함한 이러한 정의를 사용하여 기본 데이터베이스를 만듭니다.</p> +</div> + +<h3 id="데이터_쿼리하기_views.py">데이터 쿼리하기 (views.py)</h3> + +<p>장고 모델은 데이터베이스를 간단히 탐색하기 위한 쿼리 API를 제공합니다. 이 API는 다양한 조건을 통해 수 많은 필드를 빠르게 매칭시킵니다. (예를 들어, 정확하게 일치(exact), 대소문자 구분없이(case-insensitive), 해당 숫자보다 큰(greater than) 등이 있습니다.) 그리고 복잡한 쿼리문을 지원합니다. 예를 들어, 당신은 팀의 이름이 "Fr"로 시작하거나 "al"로 끝나는 U11 레벨의 팀만을 지정할 수 있습니다.</p> + +<p>굵게 표시된 줄은 모델 쿼리 API를 사용하여 <code>team_level</code> 필드의 텍트스가 정확히 'U09'인 모든 레코드를 필터링하는 방법을 보여줍니다 (이 기준이 필드 이름의 인수로 <code>filter()</code> 함수에 전달되는 방법에 유의하십시오. 일치 유형은 <strong><code>team_level__exact</code></strong>와 같이 이중 밑줄로 구분됩니다).</p> + +<pre class="brush: python notranslate">## filename: views.py + +from django.shortcuts import render +from .models import Team + +def index(request): + <strong>list_teams = Team.objects.filter(team_level__exact="U09")</strong> + context = {'youngest_teams': list_teams} + return render(request, '/best/index.html', context) +</pre> + +<dl> +</dl> + +<p>이 함수는 <code>render()</code> 함수를 사용하여 브라우저로 다시 전송되는 <code>HttpResponse</code>를 만듭니다. 지정된 HTML 템플릿과 템플릿에 삽입할 일부 데이터( "컨텍스트"라는 변수에 제공)를 결합하여 HTML 파일을 생성합니다. 다음 섹션에서는 템플릿을 생성하기 위해 템플릿에 데이터를 삽입하는 방법을 보여줍니다.</p> + +<h3 id="데이터_렌더링_HTML_템플릿">데이터 렌더링 (HTML 템플릿)</h3> + +<p>템플릿 시스템을 사용하면 페이지가 생성될 때 채워질 데이터에 자리 표시자를 사용하여 출력 문서의 구조를 지정할 수 있습니다. 템플릿은 종종 HTML을 만드는 데 사용되지만 다른 유형의 문서를 만들 수도 있습니다. 장고는 기본 템플릿 시스템과 Jinja2라는 인기있는 파이썬 라이브러리를 모두 지원합니다 (필요한 경우 다른 시스템을 지원하도록 만들 수도 있음).</p> + +<p>아래 코드는 이전 섹션의 <code>render()</code> 함수가 호출한 HTML 템플릿의 모양을 보여줍니다. 이 템플릿은 렌더링될 때 (위의 <code>render()</code> 함수 내의 컨텍스트 변수에 포함 된) "youngest_teams"라는 목록 변수에 액세스할 수 있다는 가정하에 작성되었습니다. HTML 스켈레톤에는 먼저 youngest_teams 변수가 있는지 확인한 후 <code>for</code> 루프에서 반복하는 표현식이 있습니다. 각 반복에서 템플리트는 각 팀의 <code>team_name</code> 값을 <code><li></code> 태그의 값으로 표시합니다.</p> + +<pre class="notranslate">## filename: best/templates/best/index.html + +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="utf-8"> + <title>Home page</title> +</head> +<body> + {% if youngest_teams %} + <ul> + {% for team in youngest_teams %} + <li>\{\{ team.team_name \}\}</li> + {% endfor %} + </ul> + {% else %} + <p>No teams are available.</p> + {% endif %} +</body> +</html></pre> + +<h2 id="또_무엇을_할수_있나요">또 무엇을 할수 있나요?</h2> + +<p>이전 섹션에서는 거의 모든 웹 응용 프로그램에서 사용할 주요 기능인 URL 매핑, 뷰, 모델 및 템플릿을 보여줍니다. 추가로 장고가 제공하는 기능들은 다음과 같습니다.</p> + +<ul> + <li><strong>양식</strong> : HTML 양식은 서버에서 처리할 사용자 데이터를 수집하는 데 사용됩니다. 장고는 양식 작성, 유효성 검사 및 처리를 단순화합니다.</li> + <li><strong>사용자 인증 및 권한 </strong>: 장고에는 보안을 염두에 두고 구축된 강력한 사용자 인증 및 권한 시스템이 포함되어 있습니다.</li> + <li><strong>캐싱</strong> : 컨텐츠를 동적으로 작성하는 것은 정적 컨텐츠를 제공하는 것 보다 많은 연산을 필요로 하기 때문에 느립니다. 장고는 유연한 캐싱을 제공하여 렌더링된 페이지 전체 또는 일부를 저장하여 필요할 때를 제외하고 다시 렌더링하지 않도록 할 수 있습니다.</li> + <li><strong>관리 사이트 </strong>: 기본 스켈레톤을 사용하여 앱을 만들 때 장고 관리 사이트가 기본적으로 포함됩니다. 사이트 관리자가 사이트의 모든 데이터 모델을 작성, 편집 및 볼 수있는 관리 페이지를 쉽게 제공할 수 있습니다.</li> + <li><strong>데이터 직렬화 </strong>: 장고를 사용하면 데이터를 XML 또는 JSON으로 직렬화하고 제공할 수 있습니다. 이 기능은 웹 서비스 (다른 응용 프로그램이나 사이트에서 사용하기 위해 순수하게 데이터를 제공하고 자체를 표시하지 않는 웹 사이트)를 만들거나 클라이언트 쪽 코드가 모든 데이터 렝더링을 처리하는 웹 사이트를 만들 때 유용할 수 있습니다. </li> +</ul> + +<h2 id="요약하기">요약하기</h2> + +<p>축하합니다. 이제 장고 여행의 첫발을 떼셨군요! 이제 우리는 장고의 주요 이점과 역사를 조금 알게됐고 장고 응용프로그램의 주요한 부분을 대략 이해했습니다. 또한 목록, 함수 및 클래스 구문을 포함하여 파이썬 프로그래밍 언어에 대해 몇 가지 사실을 배워야합니다.</p> + +<p>위의 실제 장고 코드를 이미 보았지만 클라이언트 측 코드와 달리 실행하기 위해서는 개발 환경을 설정해야합니다. 그것이 우리의 다음 단계입니다.</p> + +<div>{{NextMenu("Learn/Server-side/Django/development_environment", "Learn/Server-side/Django")}}</div> diff --git a/files/ko/learn/server-side/django/models/index.html b/files/ko/learn/server-side/django/models/index.html new file mode 100644 index 0000000000..03204b9df7 --- /dev/null +++ b/files/ko/learn/server-side/django/models/index.html @@ -0,0 +1,454 @@ +--- +title: 'Django Tutorial Part 3: Using models' +slug: Learn/Server-side/Django/Models +translation_of: Learn/Server-side/Django/Models +--- +<div>803{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Django/skeleton_website", "Learn/Server-side/Django/Admin_site", "Learn/Server-side/Django")}}</div> + +<p class="summary">이 문서에서는 <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a> 웹사이트의 모델을 어떻게 정의할지 보여줄 것입니다. 모델이라는 것이 무엇인지, 어떻게 선언하는지, 그리고 주된 필드 타입들에 대해서 설명합니다. 그리고 모델의 데이터에 접근할 수 있는 몇몇 방법에 대해서 간단히 보여줄 것입니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">사전 준비:</th> + <td><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django Tutorial Part 2: Creating a skeleton website</a>.</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>적절한 필드를 사용하여 모델을 설계 및 생성할 줄 알기.</td> + </tr> + </tbody> +</table> + +<h2 id="개요">개요</h2> + +<p>장고 웹 어플리케이션들은 모델이라는 파이썬 객체를 통해 데이터에 접속하고 관리합니다. 모델은 저장된 데이터의 구조를 정의합니다. 그것엔 필드 타입, 그리고 데이터의 최대 크기, 기본값, 선택 리스트 옵션, 문서를 위한 도움 텍스트, 폼을 위한 라벨 텍스트 등등이 있습니다. 모델의 정의는 기초 데이터베이스에 대해 독립적입니다 — 프로젝트 설정의 일부로 여러 옵션 중 하나를 선택할 수 있습니다. 사용할 데이터베이스를 정했다면 데이터베이스에 직접적으로 말할 필요가 없습니다 — 그저 모델 구조와 기타 코드를 작성하면, 장고가 데이터베이스와 소통하는 모든 더러운 작업을 대신해줍니다.</p> + +<p>이 튜토리얼은 <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary website</a> 예제에서 어떻게 모델을 정의하고 그것에 접근하는지에 대해 보여줍니다.</p> + +<h2 id="LocalLibrary_models_디자인하기">LocalLibrary models 디자인하기</h2> + +<p>모델을 코딩하기 전에, 우리가 어떤 데이터를 저장할 것인지, 그리고 다른 객체(object)들에 대한 관계를 어떻게 지정할 것인지 생각해 봅시다.</p> + +<p>우리는 책에 관한 정보들을 저장할 필요가 있고 (제목, 요약, 저자, 작성된 언어, 분류, ISBN) 여러 개의 사본을 사용할 수 있어야 합니다(전 세계적으로 고유한 ID, 가용성 상태 등). 저자에 대해서 그들의 이름 뿐만 아니라 더 많은 정보를 저장해야 할 수도 있습니다. 여러 명의 같거나 비슷한 이름의 저자가 있을 수도 있기 때문이죠. 우리는 정보를 책 제목, 저자, 언어, 그리고 분류에 따라 정렬할 수 있기를 원합니다.</p> + +<p>모델을 디자인할 때는 각각의 "객체(object: 관련된 정보의 모임)" 마다 분리된 모델을 가지는 것이 타당합니다. 이 예시에서 명백히 확인할 수 있는 객체(object)들은 책, 책 인스턴스, 저자입니다.</p> + +<p>선택을 웹사이트 자체에 하드코딩하는 것 보다는 모델을 사용해서 선택-리스트 옵션을 나타내도록(예시: 드롭 다운 목록)할 수 있습니다 — 이것은 모든 옵션들을 미리 알 수 없거나 옵션들이 변할 수 있을 때에 추천됩니다. 이 경우에 명백한 모델의 후보자로 책의 장르(예시: 공상 과학, 프랑스 시, 등등)와 언어(영어, 프랑스어, 한국어)가 있습니다.</p> + +<p>우리가 우리의 모델과 필드를 결정하고 나면, 우리는 그 관계에 대해서 생각해야 합니다. 장고는 당신이 그 관계를 다음과 같이 세 가지로 설정할 수 있게 하는데, 일대일(<code>OneToOneField</code>), 일대다(<code>ForeignKey</code>), 다대다(<code>ManyToManyField</code>) 관계가 그것입니다.</p> + +<p>그것들을 염두에 두고 아래의 UML 관계 다이어그램을 살펴봅시다. 이 다이어그램은 우리가 이 예시에서 정의할 모델들을 상자로 보여줍니다. 위에서 살펴본 바와 같이, 우리는 책(Book, 책의 일반적인 세부 사항들), 책 인스턴스(BookInstance, 시스템에서 사용 가능한 책의 특정한 물리적 복사본의 상태), 그리고 저자(Author)를 모델로 생성했습니다. 우리는 또한 장르(Genre)에 대한 모델을 만들어서 값들이 관리자 인터페이스에서 생성/선택이 가능하도록 만들었습니다. 우리는 <code>BookInstance:status</code>에 대한 모델을 생성하지 않았습니다 — 값들을(<code>LOAN_STATUS</code>) 하드코딩 했죠. 왜냐하면 그것은 변하지 않는 값들이기 때문입니다. 각각의 상자 안에서 모델 이름, 필드 이름과 타입, 그리고 또한 함수(method)와 그들의 반환 타입(return type)을 확인할 수 있습니다.</p> + +<p>이 다이어그램은 또한 다중도(multiplicities)을 포함한 모델 간의 관계를 보여줍니다. 다중도(multiplicities)는 관계 안에 존재하는 각각의 모델의 숫자(최대 그리고 최소)를 보여주는 다이어그램 위의 숫자입니다. 예를 들어, 상자 사이를 연결하는 선은 책과 장르가 연관되어 있다는 것을 보여줍니다. 장르(Genre) 모델에 가까이 있는 숫자들은 책이 하나 또는 그 이상의 장르(원하는 만큼 많이)를 가지고 있어야 함을 보여주는 반면, 선의 반대편 끝에 있는 책(Book) 모델 옆의 숫자들은 장르 모델이 0 또는 여러 개의 관련된 책 모델을 가질 수 있음을 보여줍니다 .</p> + +<p><img alt="LocalLibrary Model UML" src="https://mdn.mozillademos.org/files/15646/local_library_model_uml.png" style="height: 660px; width: 977px;"></p> + +<div class="note"> +<p><strong>주의</strong>: 다음 섹션은 모델이 어떻게 정의되고 사용되는지에 대한 초보적인 설명입니다. 읽으면서 위 다이어그램의 각각의 모델들을 어떻게 구성할 지 생각해 보십시오.</p> +</div> + +<h2 id="모델_입문서">모델 입문서</h2> + +<p>이 부분에서는 어떻게 모델을 정의하는지, 그리고 더 중요할 지도 모르는 필드와 필드의 인자에 대해서 간단한 개요를 제공합니다.</p> + +<h3 id="모델의_정의">모델의 정의</h3> + +<p>모델들은 보통 어플리케이션의 <strong>models.py</strong> 파일에서 정의됩니다. 이들은 <code>django.db.models.Model</code>의 서브 클래스로 구현되며 필드, 메소드 그리고 메타데이터를 포함할 수 있습니다. 아래의 코드 조각은 <code>MyModelName</code>라고 이름지어진 "전형적인" 모델을 보여줍니다:</p> + +<pre class="brush: python notranslate">from django.db import models + +class MyModelName(models.Model): + """A typical class defining a model, derived from the Model class.""" + + # Fields + my_field_name = models.CharField(max_length=20, help_text='Enter field documentation') + ... + + # Metadata + class Meta: + ordering = ['-my_field_name'] + + # Methods + def get_absolute_url(self): + """Returns the url to access a particular instance of MyModelName.""" + return reverse('model-detail-view', args=[str(self.id)]) + + def __str__(self): + """String for representing the MyModelName object (in Admin site etc.).""" + return self.field_name</pre> + +<p>아래 섹션에서 모델 안에 있는 각각의 요소들을 세부적으로 다뤄봅시다:</p> + +<h4 id="필드Fields">필드(Fields)</h4> + +<p>모델은 모든 타입의, 임의의 숫자의 필드를 가질 수 있습니다 — 각각의 필드는 우리의 데이터베이스 목록(table)에 저장하길 원하는 데이터 열(column)을 나타냅니다. 각각의 데이터베이스 레코드(행, row)는 각 필드 값들 중 하나로 구성되어 있습니다. 위의 예제를 살펴봅시다:</p> + +<pre class="brush: python notranslate">my_field_name = models.CharField(max_length=20, help_text='Enter field documentation')</pre> + +<p>위 예제는 <code>my_field_name</code>이라는 하나의 필드를 가지고 있고, <code>models.CharField</code> 타입입니다 — 즉, 이 필드가 영숫자(alphanumeric) 문자열을 포함한다는 뜻이죠. 필드 타입들은 특정한 클래스들을 사용하여 등록되며, HTML 양식(form)에서 값을 수신할 때 사용할 유효성 검증 기준과 함께 데이터베이스에 데이터를 저장하는데 사용되는 레코드의 타입을 결정합니다. 또한 필드 타입은 필드가 어떻게 저장되고 사용될지 지정하는 인수를 사용할 수 있습니다. 이 예제에서는 필드에 두 가지 인수를 줍니다:</p> + +<ul> + <li><code>max_length=20</code> — 이 필드 값의 최대 길이는 20자임을 알립니다.</li> + <li><code>help_text='Enter field documentation'</code> — 이 값이 HTML 양식(form)에서 사용자들에게 입력될 때 어떤 값을 입력해야 하는지 사용자들에게 알려주기 위해 보여주는 텍스트 라벨을 제공합니다.</li> +</ul> + +<p>필드 이름은 쿼리 및 탬플릿에서 이를 참조하는데 쓰입니다. 필드는 또한 인수로 지정된 라벨(<code>verbose_name</code>)을 가지고 있거나, 또는 필드 변수 이름의 첫자를 대문자로 바꾸고 밑줄을 공백으로 바꿔서 기본 라벨을 추정할 수 있습니다(예를 들어 <code>my_field_name</code> 은 My field name을 기본 라벨로 가지고 있습니다) .</p> + +<p>필드가 선언된 순서는 모델이 폼에서 렌더링 된다면(예시 : 관리자 사이트) 기본 순서에 영향을 미치지만, 이것은 재정렬될 수 있습니다.</p> + +<h5 id="일반적common_필드_인수">일반적(common) 필드 인수</h5> + +<p>아래의 일반적인 인수들은 많은/거의 대부분의 서로 다른 필드 타입들을 선언할 때 사용할 수 있습니다:</p> + +<ul> + <li><a href="https://docs.djangoproject.com/en/2.0/ref/models/fields/#help-text">help_text</a>: 위에서 다뤘던 것 처럼, HTML 양식(form)에 대해 텍스트 라벨을 제공합니다 (예시 : 관리자 사이트).</li> + <li><a href="https://docs.djangoproject.com/en/2.0/ref/models/fields/#verbose-name">verbose_name</a>: 필드 라벨 안에서 사용되는 인간이 읽을 수 있는 필드 이름입니다. 지정되지 않았다면, 장고가 기본 verbose_name을 필드 이름으로부터 유추합니다.</li> + <li><a href="https://docs.djangoproject.com/en/2.0/ref/models/fields/#default">default</a>: 필드를 위한 기본값입니다. 이것은 값 또는 호출 가능한 객체일 수 있습니다. 이때 객체는 새로운 레코드가 생성될 때 마다 호출됩니다.</li> + <li><a href="https://docs.djangoproject.com/en/2.0/ref/models/fields/#null">null</a>: 만약 <code>True</code>라면, 장고는 빈 <code>NULL</code> 값을 필드를 위한 데이터베이스에 저장할 것입니다(<code>CharField</code>는 대신 빈 문자열을 저장할 것입니다). 기본값은 <code>False</code>입니다.</li> + <li><a href="https://docs.djangoproject.com/en/2.0/ref/models/fields/#blank">blank</a>: 만약 <code>True</code>라면, 필드는 양식(form) 안에서 비워두는 것이 허락됩니다. 기본값은 <code>False</code>이며, 이것은 장고의 양식(form) 검증이 값을 입력하도록 강제한다는 뜻입니다. 이것은 종종 <code>null=True</code>와 함께 사용됩니다. blank 값을 허락할 때, 데이터베이스에서도 공백값을 적절하게 표시할 수 있어야 하기 때문입니다.</li> + <li><a href="https://docs.djangoproject.com/en/2.0/ref/models/fields/#choices">choices</a>: 필드를 위한 선택들의 모임입니다. 이 인수가 제공된다면, 대응하는 기본 양식(form) 위젯은 표준 텍스트 필드가 아닌 이 선택 항목을 가진 선택 상자입니다.</li> + <li><a href="https://docs.djangoproject.com/en/2.0/ref/models/fields/#primary-key">primary_key</a>: 만약 <code>True</code>라면, 현재 필드를 모델의 primary key로 설정합니다(primary key는 모든 다른 테이블 레코드들을 고유하게 확인하도록 지정된 특별한 데이터베이스 열입니다). primary key로 지정된 필드가 없다면 장고가 자동적으로 이 목적의 필드를 추가합니다.</li> +</ul> + +<p>다른 많은 옵션들이 있습니다 — 여기(<a href="https://docs.djangoproject.com/en/2.0/ref/models/fields/#field-options">full list of field options here</a>)에서 모든 필드 옵션 목록을 볼 수 있습니다.</p> + +<h5 id="일반적인common_필드_타입">일반적인(common) 필드 타입</h5> + +<p>아래의 목록은 일반적으로 사용되는 필드 타입들을 보여줍니다. </p> + +<ul> + <li><a href="https://docs.djangoproject.com/en/2.0/ref/models/fields/#django.db.models.CharField">CharField</a>는 작거나 중간 크기의 고정된 길이의 문자열을 정의할 때 사용합니다. 저장되기 위해서는 데이터의 최대 길이(<code>max_length</code>)를 정해주어야 합니다.</li> + <li><a href="https://docs.djangoproject.com/en/2.0/ref/models/fields/#django.db.models.TextField">TextField</a>는 임의의 긴 문자열에 사용됩니다. 필드의 최대 길이(<code>max_length</code>)를 지정해야 할 수도 있지만, 그것은 필드가 양식(form) 안에 표시될 때만 지정하면 됩니다(데이터베이스 레벨에서 강제되지 않습니다).</li> + <li><a href="https://docs.djangoproject.com/en/2.0/ref/models/fields/#django.db.models.IntegerField" title="django.db.models.IntegerField">IntegerField</a>은 정수값(모든 숫자)을 저장하는 필드입니다. 그리고 양식(form)에 입력된 값이 정수임을 검증하기도 합니다.</li> + <li><a href="https://docs.djangoproject.com/en/2.0/ref/models/fields/#datefield">DateField</a>와 <a href="https://docs.djangoproject.com/en/2.0/ref/models/fields/#datetimefield">DateTimeField</a>는 날짜와 날짜시간 정보를 저장, 표현하는데 사용됩니다 (각각 파이썬 <code>datetime.date</code>와 <code>datetime.datetime</code> 객체로). 이 필드들은 추가적으로 (서로 독점적인) <code>auto_now=True</code> (모델이 저장될 때 마다 필드를 현재 날짜로 설정하기 위해), <code>auto_now_add</code> (모델이 처음 생성되었을 때만 날짜를 설정하기 위해) , 그리고 <code>default</code> (사용자에 의해 변경될 수 있는 기본 날짜를 설정하기 위해) 매개 변수를 선언할 수 있습니다.</li> + <li><a href="https://docs.djangoproject.com/en/2.0/ref/models/fields/#emailfield">EmailField</a>는 이메일 주소를 저장하고 검증하기 위해 사용합니다.</li> + <li><a href="https://docs.djangoproject.com/en/2.0/ref/models/fields/#filefield">FileField</a>와 <a href="https://docs.djangoproject.com/en/2.0/ref/models/fields/#imagefield">ImageField</a>는 각각 파일과 이미지를 업로드하기 위해 사용됩니다 (<code>ImageField</code>는 단지 업로드된 파일이 이미지임을 확인하는 추가 검증을 더할 뿐입니다). 이것들은 업로드된 파일들이 어디에 어떻게 저장되는지 정의하는 매개 변수를 가집니다.</li> + <li><a href="https://docs.djangoproject.com/en/2.0/ref/models/fields/#autofield">AutoField</a>는 자동적으로 증가하는 <code>IntegerField</code>의 특별한 타입입니다. 이 타입의 primary key는 명시적으로 지정하지 않는 이상 모델에 자동적으로 추가됩니다.</li> + <li><a href="https://docs.djangoproject.com/en/2.0/ref/models/fields/#foreignkey">ForeignKey</a>는 다른 데이터베이스 모델과 일대다 관계를 지정하기 위해 사용됩니다 (예시: 차는 하나의 제조사를 갖고 있지만 제조사는 많은 차들을 만들 수 있습니다). 일대다에서 "일"쪽이 key를 포함하는 모델입니다.</li> + <li><a href="https://docs.djangoproject.com/en/2.0/ref/models/fields/#manytomanyfield">ManyToManyField</a>는 다대다 관계를 지정하기 위해 사용됩니다 (예시: 책은 여러 장르를 가질 수 있고, 각각의 장르에도 많은 책들이 있습니다). 우리 예제인 도서관 어플리케이션에서는 이 필드를 <code>ForeignKeys</code>와 매우 유사하게 사용할 겁니다. 하지만 그룹 사이의 관계를 보여주기 위해서는 더욱 복잡한 방식으로 사용될 수 있습니다. 이것은 레코드가 삭제됐을 때 어떤 일이 일어나는지 정의하기 위해 <code>on_delete</code> 매개변수를 가집니다 (예시: <code>models.SET_NULL</code>의 값은 단순히 <code>NULL</code>값으로 설정될 겁니다).</li> +</ul> + +<p>다른 많은 타입의 필드들이 많이 있습니다. 서로 다른 타입의 숫자를 위한 필드 (큰 정수, 작은 정수, 부동소수(float)), 불리언(booleans), URL, slug, unique id, 그리고 다른 "시간-관련된" 정보들(duration, time, 등등)들을 포함해서요. 모든 목록을 여기(<a href="https://docs.djangoproject.com/en/2.0/ref/models/fields/#field-types">full list here</a>)에서 확인할 수 있습니다.</p> + +<h4 id="메타데이터">메타데이터</h4> + +<p>아래와 같이 <code>class Meta</code>를 선언하여 모델에 대한 모델-레벨의 메타데이타를 선언할 수 있습니다.</p> + +<pre class="brush: python notranslate">class Meta: + ordering = ['-my_field_name'] +</pre> + +<p>이 메타데이터의 가장 유용한 기능들 중 하나는 모델 타입을 쿼리(query)할 때 반환되는 기본 레코드 순서를 제어하는 것입니다. 이렇게 하려면 위와 같이 필드 이름 목록의 일치 순서를 <code>ordering</code> 속성에 지정해야 합니다. 순서는 필드의 타입에 따라 달라질 것입니다(문자 필드는 알파벳 순서에 따라 정렬될 것이고, 반면 날짜 필드는 날짜순으로 정렬될 것입니다). 위와 같이, 반대로 정렬하고 싶다면 마이너스 기호(-)를 필드 이름 앞에 접두사로 붙이면 됩니다.</p> + +<p>예를 들어, 우리가 기본적으로 아래와 같이 책들을 정렬하려고 한다면:</p> + +<pre class="brush: python notranslate">ordering = ['title', '-pubdate']</pre> + +<p>책들은 A-Z까지 알파벳 순으로 정렬되고, 그 후에는 제목(title) 안에 있는 발행일 별로 가장 최근 것부터 가장 오래된 것 순으로 정렬될 것입니다.</p> + +<p>다른 일반적인(common) 속성은 <code>verbose_name</code>이며, 단일 및 복수 형식(form)의 클래스를 위한 자세한(verbose) 이름입니다:</p> + +<pre class="brush: python notranslate">verbose_name = 'BetterName'</pre> + +<p>다른 유용한 속성들은 모델을 위한 새로운 "접근 권한"을 생성 및 적용 가능하게 하며(기본 권한은 자동적으로 적용됨), 다른 필드에 기반한 순서 정렬을 허용하거나, 또는 클래스가 "추상(abstract: 레코드를 생성할 수 없고, 대신 다른 모델들을 만들기 위해 파생되는 기본 클래스)"임을 선언할 수 있습니다.</p> + +<p>여러가지 메타데이터 옵션들은 모델에 무슨 데이터베이스를 사용해야만 하는가 그리고 데이터가 어떻게 저장되는가를 제어한다 (이것들은 모델을 기존 데이터베이스에 매핑할 때만 유용하다).</p> + +<p>메타데이터 옵션의 모든 목록은 여기에서 볼 수 있습니다: <a href="https://docs.djangoproject.com/en/2.0/ref/models/options/">Model metadata options</a> (장고 문서).</p> + +<h4 id="메소드Methods">메소드(Methods)</h4> + +<p>모델은 또한 메소드를 가질 수 있습니다.</p> + +<p><strong><code><font face="Open Sans, arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;">최소한, 모든 모델마다 표준 파이썬 클래스의 메소드인 </span></font>__str__()</code> 을 정의하여 각각의 object가 사람이 읽을 수 있는 문자열을 반환(return)하도록 합니다.</strong> 이 문자열은 관리자 사이트에 있는 개별적인 레코드들을 보여주는 데 사용됩니다(그리고 모델 인스턴스를 참조해야 하는 다른 모든 곳에도요). 종종 이것은 모델에서 제목(title)이나 이름 필드(name field)를 반환할 것입니다 .</p> + +<pre class="brush: python notranslate">def __str__(self): + return self.field_name</pre> + +<p>장고 모델에 포함할 다른 일반적인 메소드는 <code>get_absolute_url()</code>입니다. 웹사이트의 개별적인 모델 레코드들을 보여주기 위한 URL을 반환하는 메소드입니다(만약 이 메소드를 정의했다면 장고는 관리자 사이트 안의 모델 레코드 수정 화면에 "View on Site" 버튼을 자동적으로 추가할 것입니다). 아래에서 <code>get_absolute_url()</code>의 표준적인 사용을 볼 수 있습니다.</p> + +<pre class="brush: python notranslate">def get_absolute_url(self): + """Returns the url to access a particular instance of the model.""" + return reverse('model-detail-view', args=[str(self.id)]) +</pre> + +<div class="note"> +<p><strong> 주의</strong>: 모델의 개별적인 레코드들을 보여주기 위해서 <code>/myapplication/mymodelname/2</code> 와 같은 URL을 사용한다고 가정한다면("2"는 특정한 레코드를 위한 <code>id</code> 입니다), 응답과 id를 "모델 디테일 뷰(model detail view)"에 전달하기 위해 (레코드를 표시하기 위한 작업을 할) URL 매퍼를 만들 필요가 있습니다 . 위의 <code>reverse()</code> 함수는 알맞은 포맷의 URL을 생성하기 위해서 URL 매퍼를(위 경우에선 'model-detail-view'라고 명명됨) "반전" 시킬 수 있습니다.</p> + +<p> 물론 이것이 작동하기 위해선 URL 매핑, 뷰, 그리고 탬플릿을 작성해야 합니다!</p> +</div> + +<p>또한 원하는 메소드를 정의해서 (그들이 어떤 변수도 가지고 있지 않다면) 코드나 탬플릿에서 불러올 수 있습니다.</p> + +<h3 id="모델_관리management">모델 관리(management)</h3> + +<p>모델 클래스들을 정의한 이후엔 클래스들을 사용해서 레코드들을 생성, 업데이트, 또는 삭제할 수 있고, 모든 레코드 또는 레코드의 특정 하위 집합을 가져오기 위해 쿼리를 실행할 수 있습니다. 튜토리얼에서 뷰를 정의할 때 그 방법을 보여줄 것이지만, 아래에 간략한 요약이 있습니다.</p> + +<h4 id="레코드의_생성과_수정">레코드의 생성과 수정</h4> + +<p>레코드를 생성하려먼 모델의 인스턴스를 정의하고 <code>save()</code>를 호출할 수 있습니다.</p> + +<pre class="brush: python notranslate"># Create a new record using the model's constructor. +record = MyModelName(my_field_name="Instance #1") + +# Save the object into the database. +record.save() +</pre> + +<div class="note"> +<p><strong>Note</strong>: 만약 당신이 어떤 필드도 <code>primary_key</code>를 선언하지 않았다면, 새로운 레코드는 자동적으로 <code>id</code>라는 필드 이름을 가진 <code>primary_key</code>가 주어지게 됩니다. 위의 레코드를 저장한 후 이 <code>id</code> 필드를 쿼리할 수 있는데, 1의 값을 가질 겁니다.</p> +</div> + +<p>이 새로운 레코드 안의 필드에 점 구문(.)을 사용해서 접근하여 값을 변경할 수 있습니다. 수정된 값들을 데이터베이스에 저장하기 위해 <code>save()</code>를 호출해야 합니다.</p> + +<pre class="brush: python notranslate"># Access model field values using Python attributes. +print(record.id) # should return 1 for the first record. +print(record.my_field_name) # should print 'Instance #1' + +# Change record by modifying the fields, then calling save(). +record.my_field_name = "New Instance Name" +record.save()</pre> + +<h4 id="레코드_검색하기">레코드 검색하기</h4> + +<p>모델의 객체(<code>objects</code>) 속성(기본 클래스에서 제공됨)을 사용하여 특정 기준과 일치하는 레코드를 검색할 수 있습니다.</p> + +<div class="note"> +<p><strong> 주의:</strong> "추상(abstract)" 모델과 필드 이름을 사용하여 레코드들을 검색하는 방법을 설명하는 것은 조금 혼란스러울 수 있습니다. 아래에서는 <code>title</code>과 <code>genre</code> 필드가 있는 <code>Book</code> 모델을 참조하겠습니다. 이 때 <code>genre</code>는 또한 <code>name</code>이라는 단일 필드를 가지고 있는 모델입니다.</p> +</div> + +<p>우리는 <code>objects.all()</code>을 사용하여 모델의 모든 레코드들을 <code>QuerySet</code>으로 가져올 수 있습니다. <code>QuerySet</code>은 반복가능한(iterable) 객체이며, 이것은 반복/루프할 수 있는 많은 객체들을 포함하고 있다는 의미입니다.</p> + +<pre class="brush: python notranslate">all_books = Book.objects.all() +</pre> + +<p> 장고의 <code>filter()</code>는 반환된 <code>QuerySet</code>이 지정된 문자(<strong>text</strong>) 또는 숫자(<strong>numeric</strong>)<strong> </strong>필드를 특정한 기준에 맞추어 필터링할 수 있게 합니다. 예를 들어서, "wild"를 제목 안에 포함하는 책들을 필터링하여 그 숫자를 세어 보려면, 아래와 같이 하면 됩니다.</p> + +<pre class="brush: python notranslate">wild_books = Book.objects.filter(title__contains='wild') +number_wild_books = Book.objects.filter(title__contains='wild').count() +</pre> + +<p>기준이 될 필드와 타입은 필터 매개 변수 이름에서 정의됩니다. 다음 포맷을 이용해서요: <code>field_name__match_type</code> (주의: 위의 <code>title</code>과 <code>contains</code> 사이 밑줄은 두 개입니다). 위에서 우리는 대소문자를 구분하여 <code>title</code>을 필터링합니다. 다른 많은 유형의 일치 방법이 있습니다: <code>icontains</code>(대소문자를 구분하지 않음), <code>iexact</code>(대소문자를 구분하지 않는 정확히 일치), <code>exact</code>(대소문자를 구분하는 정확한 일치) 그리고 <code>in</code>, <code>gt</code>(보다 더 큰(greater than)), <code>startswith</code> 등등이 있습니다. 모든 일치방법 목록은 여기(<a href="https://docs.djangoproject.com/en/2.0/ref/models/querysets/#field-lookups">full list is here</a>) 있습니다.</p> + +<p>어떤 경우엔 일대다 관계를 다른 모델에 정의하는 필드를 필터링해야 할 때도 있습니다(예:<code>ForeignKey</code>). 이 경우에 추가적인 이중 밑줄을 사용하여 관련 모델 안의 필드에 "색인(index)"할 수 있습니다. 예를 들어 특정한 장르 패턴을 가진 책들을 필터링하려면, 아래와 같이 <code>genre</code> 필드를 통해서 <code>name</code>에 색인(index)해야 할 겁니다.</p> + +<pre class="brush: python notranslate"># Will match on: Fiction, Science fiction, non-fiction etc. +books_containing_genre = Book.objects.filter(genre<strong>__</strong>name<strong>__</strong>icontains='fiction') +</pre> + +<div class="note"> +<p><strong> 주의</strong>: 밑줄(__)을 사용하여 원하는 만큼 다양한 레벨의 관계(<code>ForeignKey</code>/<code>ManyToManyField</code>)를 탐색할 수 있습니다. 예를 들어서 추가적인 "cover" 관계를 사용하여 정의된 다른 타입의 <code>Book</code>은 다음과 같은 매개 변수 이름을 가질겁니다 :<code>type__cover__name__exact='hard'.</code></p> +</div> + +<p>관련된 모델의 역방향 검색, 필터 변경, 값의 더 작은 집합 반환하기 등 쿼리로 할 수 있는 일들은 더욱 많이 있습니다. 더 많은 정보를 보려면 <a href="https://docs.djangoproject.com/en/2.0/topics/db/queries/">Making queries</a> (장고 문서)를 참고하세요.</p> + +<h2 id="LocalLibrary_모델_정의하기">LocalLibrary 모델 정의하기</h2> + +<p>이 섹션에서는 도서관을 위한 모델을 정의하기 시작할 겁니다. models.py ( /locallibrary/catalog/에 있음)파일을 여세요. 페이지 상단의 표준 코드(boilerplate)는 우리들의 모델이 상속받을 모델 기본 클래스 <code>models.Model</code>을 포함하는 models 모듈을 가져옵니다.</p> + +<pre class="brush: python notranslate">from django.db import models + +# Create your models here.</pre> + +<h3 id="장르Genre_모델">장르(Genre) 모델</h3> + +<p>아래의 장르(<code>Genre</code>) 모델 코드를 복사해서 <code>models.py</code> 파일에 붙여넣기 하세요. 이 모델은 책 카테고리에 관한 정보를 저장하는데 사용됩니다 — 예를 들어 소설인지, 논픽션인지, 로맨스인지 군사 역사물인지 등등. 위에서 말했던 것 처럼, 우리는 장르를 자유 텍스트나 선택 목록으로 만들지 않고 모델을 이용해 만들었습니다. 가능한 값들이 하드코딩되기 보다는 데이터베이스를 통해 관리되도록 하기 위해서입니다.</p> + +<pre class="brush: python notranslate">class Genre(models.Model): + """Model representing a book genre.""" + name = models.CharField(max_length=200, help_text='Enter a book genre (e.g. Science Fiction)') + + def __str__(self): + """String for representing the Model object.""" + return self.name</pre> + +<p><code><font face="Arial, x-locale-body, sans-serif"><span style="background-color: #ffffff;">모델은 하나의 </span></font>CharField</code> 필드(<code>name</code>)을 가지고 있습니다. 이것은 장르의 이름을 나타냅니다 . 이것은 200자로 제한되어 있고 <code>help_text</code>를 갖고 있습니다. 모델의 마지막에서 우리는 <code>__str__()</code> 메소드를 선언합니다. 이 메소드는 특정한 레코드에 의해 정의된 장르의 이름을 단지 반환합니다. 아무런 자세한 이름(verbose name)도 정의되지 않았기 때문에, 필드는 폼(form)에서 <code>Name</code>으로 호출(call)될 겁니다.</p> + +<h3 id="책Book_모델">책(Book) 모델</h3> + +<p>아래의 책(Book) 모델을 복사해서 파일의 아래에 붙여넣기 하세요. 책 모델은 일반적으로 사용 가능한 책에 대한 모든 정보들을 보여주지만, 대여 가능한 특정한 물리적 "인스턴스(instance)"나 "복사본(copy)"은 보여주지 않습니다. 모델은 <code>CharField</code>를 사용하여 책의 <code>title</code>과 <code>isbn</code>을 나타냅니다(<code>isbn</code>이 이름을 지정하지 않은 첫 번째 매개변수를 사용하여 라벨을 "ISBN"으로 지정한 것에 주목하세요. 만약 그러지 않았다면 기본 라벨은 "Isbn"이었을 것입니다). 텍스트가 상당히 길 것이기 때문에 <code>summery</code>에는 <code>TextField</code>를 사용합니다.</p> + +<pre class="brush: python notranslate">from django.urls import reverse # Used to generate URLs by reversing the URL patterns + +class Book(models.Model): + """Model representing a book (but not a specific copy of a book).""" + title = models.CharField(max_length=200) + author = models.ForeignKey('Author', on_delete=models.SET_NULL, null=True) + + # Foreign Key used because book can only have one author, but authors can have multiple books + # Author as a string rather than object because it hasn't been declared yet in the file. + summary = models.TextField(max_length=1000, help_text='Enter a brief description of the book') + isbn = models.CharField('ISBN', max_length=13, help_text='13 Character <a href="https://www.isbn-international.org/content/what-isbn">ISBN number</a>') + + # ManyToManyField used because genre can contain many books. Books can cover many genres. + # Genre class has already been defined so we can specify the object above. + genre = models.ManyToManyField(Genre, help_text='Select a genre for this book') + + def __str__(self): + """String for representing the Model object.""" + return self.title + + def get_absolute_url(self): + """Returns the url to access a detail record for this book.""" + return reverse('book-detail', args=[str(self.id)]) +</pre> + +<p>장르는 책이 여러 개의 장르를 가지고, 장르도 여러 개의 책을 가질 수 있는 다대다 필드(<code>ManyToManyField</code>)입니다. 저자는 <code>ForeignKey</code> 로 선언됩니다. 따라서 각각의 책은 하나의 저자만 가질 수 있지만, 저자는 여러 개의 책들을 가질 수 있습니다(실제로는 책이 여러 명의 작가를 가질 수 있지만, 이 구현에서는 아닙니다!).</p> + +<p> 두 필드 타입들 안에서 관련된 모델 클래스는 모델 클래스나 관련된 모델의 이름을 포함하는 문자열을 사용하여 이름없는 첫 번째 매개 변수로 선언됩니다. 연관된 클래스가 참조되기 전에 파일 안에서 아직 정의되지 않았다면 모델의 이름을 문자열로 사용해야 합니다! 저자 ( <code>author</code> )필드에서 관심을 가져야 할 다른 변수는 <code>null=True</code>와 <code>on_delete=models.SET_NULL</code>입니다. <code>null=True</code>는 어떤 저자도 선택되지 않았다면 데이터베이스에 <code>Null</code> 값을 저장하도록 하고, <code>on_delete=models.SET_NULL</code>은 관련된 저자(author) 레코드가 삭제되었을 때 저자(author)의 값을 <code>Null</code>로 설정할 겁니다.</p> + +<p>모델은 또한 <code>Book</code> 레코드를 나타내는 책의 <code>title</code> 필드를 사용하여 <code>__str__()</code> 를 정의합니다. 마지막 메소드 <code>get_absolute_url()</code> 은 이 모델의 세부 레코드에 접근하는 데에 사용될 수 있는 URL을 반환합니다 (이것이 작동하도록 하기 위해선 <code>book-detail</code>이라는 이름의 URL 매핑을 정의하고, 관련 뷰와 탬플릿을 정의해야 합니다).</p> + +<h3 id="책_인스턴스BookInstance_모델">책 인스턴스(BookInstance) 모델</h3> + +<p> 다음으로, <code>BookInstance</code> 모델(아래에 있는)을 다른 모델들 아래에 복사하세요. <code>BookInstance</code> 은 누군가 빌릴지도 모를 특정한 책의 복사본을 나타냅니다. 그리고 복사본이 사용 가능한지 여부, 언제 되돌려받을 수 있을지, "출판사(imprint)" 또는 버전 세부 사항, 그리고 도서관 안에 있는 책의 고유 id에 대한 정보를 포함합니다.</p> + +<p> 이제 몇몇 필드와 메소드는 친숙할 겁니다. BookInstance 모델은 아래를 사용합니다</p> + +<ul> + <li><code>ForeignKey</code> : 연관된 <code>Book</code> 을 식별하기 위해(각각의 책은 많은 복사본을 가질 수 있지만, 복사본은 하나의 <code>Book</code>만을 가질 수 있음).</li> + <li><code>CharField</code> : 책의 출판사(imprint)(특정한 발간일)을 나타내기 위해.</li> +</ul> + +<pre class="brush: python notranslate">import uuid # Required for unique book instances + +class BookInstance(models.Model): + """Model representing a specific copy of a book (i.e. that can be borrowed from the library).""" + id = models.UUIDField(primary_key=True, default=uuid.uuid4, help_text='Unique ID for this particular book across whole library') + book = models.ForeignKey('Book', on_delete=models.SET_NULL, null=True) + imprint = models.CharField(max_length=200) + due_back = models.DateField(null=True, blank=True) + + LOAN_STATUS = ( + ('m', 'Maintenance'), + ('o', 'On loan'), + ('a', 'Available'), + ('r', 'Reserved'), + ) + + status = models.CharField( + max_length=1, + choices=LOAN_STATUS, + blank=True, + default='m', + help_text='Book availability', + ) + + class Meta: + ordering = ['due_back'] + + def __str__(self): + """String for representing the Model object.""" + return f'{self.id} ({self.book.title})'</pre> + +<p>추가적으로 몇 가지 새로운 타입의 필드를 선언합니다:</p> + +<ul> + <li> <code>UUIDField</code> 는 <code>id</code> 필드가 이 모델의 <code>primary_key</code> 로 설정되는 데 사용됩니다. 이 타입의 필드는 각 인스턴스에 전역적으로 고유한 값을 할당합니다 (도서관에서 찾을 수 있는 모든 책 마다 하나씩).</li> + <li><code>DateField</code> 는 <code>due_back</code> (만기일) 날짜에 사용됩니다 (책이 빌려지거나 유지 보수된 이후 사용할 수 있을 것으로 예상되는 날짜). 이 값은 <code>blank</code> 나 <code>null</code> 이 될 수 있습니다(책을 사용하 할 수 있는 경우 필요). 메타데이터 모델 (<code>Class Meta</code>) 은 레코드들이 쿼리에서 반환되었을 때 레코드들을 정렬하기 위해서 이 필드를 사용합니다 .</li> + <li><code>status</code> 는 선택/선택 목록(choice/selection list)을 정의하는 <code>CharField</code> 입니다. 보시다시피, 우리는 열쇠-값(key-value) 쌍의 튜플(tuple)을 포함하는 튜플을 정의해서 choices 인자에 전달합니다. 열쇠/값(key/value) 쌍에서 값(value)은 사용자가 선택할 수 있는 표시값인 반면, 열쇠(key)는 그 옵션이 선택되었을 때 실제로 저장되는 값입니다. 또한 책이 선반에 저장되기 전에는 사용할 수 없으므로 기본값인 'm'(유지 관리, maintenanace)을 설정했습니다.</li> +</ul> + +<p> 모델 <code> __str__()</code> 은 그것의 고유한 id 그리고 연관된 <code>Book</code>의 제목을 조합하여 <code>BookInstance</code> 객체를 나타냅니다.</p> + +<div class="note"> +<p><strong>주의</strong>: 조금의 파이썬:</p> + +<ul> + <li>파이썬 3.6에서부터 문자열 보간 구문을 쓸 수 있습니다 (f-strings로 잘 알려진): <code>f'{self.id} ({self.book.title})'</code>.</li> + <li>이 튜토리얼의 옛 버전에서는 <a href="https://www.python.org/dev/peps/pep-3101/">formatted string</a> 구문을 사용했고, 이것 또한 파이썬 안에 문자열을 형식화(formatting)하는 유효한 방법입니다 (예 : <code>'{0} ({1})'.format(self.id,self.book.title)</code>).</li> +</ul> +</div> + +<h3 id="저자Author_모델">저자(Author) 모델</h3> + +<p> <strong>models.py </strong>안에 작성된 코드 아래에 <code>Author</code> 모델을 복사 붙여넣기 하세요 (아래에 있습니다).</p> + +<p> 이제 모든 필드/메소드들이 익숙할 겁니다. 모델은 저자를 이름(first name), 성(last name), 생일, 그리고 (선택적으로) 사망일을 가진다고 정의합니다. 기본적으로 <code>__str__()</code> 는 name을 첫째로 성(last name), 그 다음 이름(first name)이 오는 순서로 반환합니다. <code>get_absolute_url()</code> 메소드는 개별 저자를 나타내기 위한 URL을 가져오기 위해 <code>author-detail</code> URL 매핑을 반대로 합니다.</p> + +<pre class="brush: python notranslate">class Author(models.Model): + """Model representing an author.""" + first_name = models.CharField(max_length=100) + last_name = models.CharField(max_length=100) + date_of_birth = models.DateField(null=True, blank=True) + date_of_death = models.DateField('Died', null=True, blank=True) + + class Meta: + ordering = ['last_name', 'first_name'] + + def get_absolute_url(self): + """Returns the url to access a particular author instance.""" + return reverse('author-detail', args=[str(self.id)]) + + def __str__(self): + """String for representing the Model object.""" + return f'{self.last_name}, {self.first_name}' + +</pre> + +<h2 id="데이터베이스_마이그레이션_재실행하기"> 데이터베이스 마이그레이션 재실행하기</h2> + +<p> 모든 모델이 생성되었습니다. 이제 데이터베이스 migration을 재실행하여 모델들을 데이터베이스에 추가하세요.</p> + +<pre class="notranslate"><code>python3 manage.py makemigrations +python3 manage.py migrate</code></pre> + +<h2 id="도전과제_-_언어Language_모델">도전과제 - 언어(Language) 모델</h2> + +<p> 지역 후원자가 다른 언어로 저술된 새로운 책들을 후원한다고 생각해 보세요(아마도, 프랑스어?). 도전과제는 이것이 도서관 웹사이트에서 이것을 가장 잘 나타낼 수 있는 방법을 찾아내고, 모델에 추가하는 것입니다.</p> + +<p>고려해야 할 사항들:</p> + +<ul> + <li>"언어"(language)는 <code>Book</code>, <code>BookInstance</code>, 아니면 어떤 다른 객체와 연관되어야 할까요?</li> + <li> 서로 다른 언어들은 모델로 나타내어야 할까요? 아니면 자유 텍스트 필드?그것도 아니라면 하드-코딩된 선택 리스트로 나타내어야 할까요?</li> +</ul> + +<p>결정을 내린 후에, 필드를 추가하세요. 우리가 선택한 것은 여기(<a href="https://github.com/mdn/django-locallibrary-tutorial/blob/master/catalog/models.py">here</a>) 깃허브에서 볼 수 있습니다.</p> + +<ul> +</ul> + +<ul> +</ul> + +<h2 id="요약">요약</h2> + +<p> 이 글에서 우리는 모델이 어떻게 정의되는지 배웠고, 이 정보를 지역 도서관 웹사이트를 위한 적절한 모델을 설계하고 구현하기 위해 사용했습니다.</p> + +<p>At this point we'll divert briefly from creating the site, and check out the <em>Django Administration site</em>. This site will allow us to add some data to the library, which we can then display using our (yet to be created) views and templates.</p> + +<h2 id="See_also">See also</h2> + +<ul> + <li><a href="https://docs.djangoproject.com/en/2.0/intro/tutorial02/">Writing your first Django app, part 2</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.0/topics/db/queries/">Making queries</a> (Django Docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.0/ref/models/querysets/">QuerySet API Reference</a> (Django Docs)</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Django/skeleton_website", "Learn/Server-side/Django/Admin_site", "Learn/Server-side/Django")}}</p> + + + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Server-side/Django/Introduction">Django introduction</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/development_environment">Setting up a Django development environment</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Django Tutorial: The Local Library website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django Tutorial Part 2: Creating a skeleton website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Models">Django Tutorial Part 3: Using models</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Admin_site">Django Tutorial Part 4: Django admin site</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django Tutorial Part 5: Creating our home page</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Generic_views">Django Tutorial Part 6: Generic list and detail views</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Sessions">Django Tutorial Part 7: Sessions framework</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Authentication">Django Tutorial Part 8: User authentication and permissions</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Forms">Django Tutorial Part 9: Working with forms</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Testing">Django Tutorial Part 10: Testing a Django web application</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Django Tutorial Part 11: Deploying Django to production</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/web_application_security">Django web application security</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></li> +</ul> diff --git a/files/ko/learn/server-side/django/sessions/index.html b/files/ko/learn/server-side/django/sessions/index.html new file mode 100644 index 0000000000..59634c6c36 --- /dev/null +++ b/files/ko/learn/server-side/django/sessions/index.html @@ -0,0 +1,190 @@ +--- +title: 'Django Tutorial Part 7: Sessions framework' +slug: Learn/Server-side/Django/Sessions +translation_of: Learn/Server-side/Django/Sessions +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Django/Generic_views", "Learn/Server-side/Django/authentication_and_sessions", "Learn/Server-side/Django")}}</div> + +<p class="summary">이 튜토리얼에서는 <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a> website을 확장시킬 것입니다. 방문 수를 셀 수 있는 session-based 기능을 더한 홈페이지입니다. 이것은 상대적으로 간단한 예제인데, 이는 당신의 홈페이지에서 익명의 유저들에게 지속적으로 서비스를 제공하는 session framework의 사용법입니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Prerequisites:</th> + <td>Complete all previous tutorial topics, including <a href="/en-US/docs/Learn/Server-side/Django/Generic_views">Django Tutorial Part 6: Generic list and detail views</a></td> + </tr> + <tr> + <th scope="row">Objective:</th> + <td>To understand how sessions are used.</td> + </tr> + </tbody> +</table> + +<h2 id="개요">개요</h2> + +<p>이전 튜토리얼에서 우리가 만든 <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a> website는 카탈로그에서 유저가 책과 저자를 검색할 수 있도록 합니다. 컨텐츠가 Database로부터 다이나믹하게 생성되기 때문에, 모든 유저는 사용시에 필수적으로 같은 페이지와 정보 타입에 필수적으로 접근할 것입니다.</p> + +<p>실제 도서관에서는 각각의 유저들에게 그들의 이전 사이트 사용과 선호 등에 기반한 커스텀된 경험을 제공하고 싶을지도 모릅니다 . 예를 들어, 유저가 이미 알고 있는 경고 메세지들을 숨길 수도 있습니다. 그 유저들이 다음에 사이트를 방문하거나 그들의 선호사항(e.g. 그들이 각 페이지에서 보여지길 원하는 검색의 결과 수)에 대해서 저장하는 것을 말합니다. </p> + +<p>session framework는 당신이 이 행동의 분류하도록 하며, 각 사이트 방문자에 기반한 임의의 데이터를 검색하거나 저장하도록 합니다. </p> + +<h2 id="세션이란">세션이란?</h2> + +<p>웹 브라우저와 서버가 HTTP 프로토콜을 통해서 하는 모든 커뮤니케이션은 무상태(stateless)라고 합니다. 프로토콜이 무상태라는 뜻은 클라이언트와 서버 사이의 메시지가 완벽하게 각각 독립적이라는 뜻입니다. — 여기엔 이전 메시지에 근거한 행동이나 순서(sequence)라는 것이 존재하지 않습니다. 결국, 만약 사이트가 클라이언트와 계속적인 관계를 유지하는 것을 당신이 원한다면, 당신이 직접 그 작업을 해야합니다.</p> + +<p>세션이라는 것은 Django 그리고 대부분의 인터넷에서 사용되는 메카니즘으로, 사이트와 특정 브라우저 사이의 "state"를 유지시키는 것입니다. 세션은 당신이 매 브라우저마다 임의의 데이터를 저장하게 하고, 이 데이터가 브라우저에 접속할 때 마다 사이트에서 활용될 수 있도록 합니다. 세션에 연결된 각각의 데이터 아이템들은 "key"에 의해 인용되고, 이는 또다시 데이터를 찾거나 저장하는 데에 이용됩니다.</p> + +<p>장고는 특정 <em>session id</em> 를 포함하는 쿠키를 사용해서 각각의 브라우저와 사이트가 연결된 세션을 알아냅니다. 실질적인 세션의 <em>data</em> 사이트의 Database에 기본 설정값으로 저장됩니다 (이는 쿠키안에 데이터를 저장하는 것보다 더 보안에 유리하고, 쿠키는 악의적인 사용자에게 취약합니다). 당신은 Django를 다른 장소 (캐시, 파일, "보안이 된" 쿠키)에 저장하도록 설정할 수 있지만, 그러나 기본 위치가 상대적으로 더 안전합니다.</p> + +<h2 id="세션_사용설정하기">세션 사용설정하기</h2> + +<p>세션설정은 처음에 skeleton website를 생성했을 때 (in tutorial 2) 자동으로 사용할 수 있도록 설정되었습니다. </p> + +<p>세션사용설정은 프로젝트 settings.py에서 아래와 같이 <code>INSTALLED_APPS</code> 와 <code>MIDDLEWARE</code> 부분에 있습니다.</p> + +<pre class="brush: python">INSTALLED_APPS = [ + ... +<strong> 'django.contrib.sessions',</strong> + .... + +MIDDLEWARE = [ + ... +<strong> 'django.contrib.sessions.middleware.SessionMiddleware',</strong> + ....</pre> + +<h2 id="세션_사용하기">세션 사용하기</h2> + +<p><code>session</code> 속성은 <code>request</code> parameter 에서 파생된 view 안에 있습니다. ( view 로 전달되는 H<code>ttpRequest </code> 의 첫번째 함수 ). 이 세션의 속성은 현재의 사용자(정확히는 브라우저) 의 site 에 대한 connection 을 의미합니다. 브라우저의 cookie 안에 정의 되어 있습니다.</p> + +<p>이 <code>session</code> 속성은 사전 같은 객체인데 여러번 읽고 쓰고 심지어 수정까지 가능합니다.여러분은 다양한 dictionary 연산 - 즉, 모든 데이타 삭제, Key 가 존재하는지 데이타를 통한 looping 기타등등. 무엇보다 표준적인 "dictionary" API 를 통해 값을 가져오거나 저장 할 수 있습니다.</p> + +<p>아래 코드는 key 값이 "my_car" 인 데이타를 어떻게 읽고 쓰고 삭제하는지 보여줍니다. 물론 그 key 값은 현재의 session (브자우져와 싸이트의 연결정보) 과 연관되어진 key 입니다.</p> + +<div class="note"> +<p><strong>Note</strong>: 장고가 대단한점 한가지는 여러분이 이런 session 의 매카니즘에 생각하지 않게끔 한다는 점입니다. 만일 view 안에 있는 아래의 code 를 사용하면 <strong>오직 현재의 브라우저만</strong>이 현재의 request 에 관한 <code>my_car</code> 정보를 알 수 있다는 겁니다. </p> +</div> + +<pre class="brush: python"># Get a session value by its key (e.g. 'my_car'), raising a KeyError if the key is not present +my_car = request.session['my_car'] + +# Get a session value, setting a default if it is not present ('mini') +my_car = request.session.get('my_car', 'mini') + +# Set a session value +request.session['my_car'] = 'mini' + +# Delete a session value +del request.session['my_car'] +</pre> + +<p>이 API 는 또한 여러가지 다른 방법을 제공하는데 그들은 대부분 관련된 session cookie 를 다루는데 사용되는 것들 입니다. 예를 들어, 그 cookies 가 사용자의 브라우져에서 지원이 되는지 태스트하거나, 만기일을 알아본다던지, 만기된 session 을 삭제 한다던지. 좀더 알아보고 싶다면 <a href="https://docs.djangoproject.com/en/2.0/topics/http/sessions/">How to use sessions</a> (Django docs) 에서 그 API 를 배울수 있습니다.</p> + +<h2 id="세션_데이터_저장하기">세션 데이터 저장하기</h2> + +<p>기본적으로 장고는 세션 데이타를 세션 database 에 저장합니다. 그리고 그 session cookie 를 필요할때 client 에게로 내려보내는 거지요. 즉, session 정보가 변경되었거나 삭제 되었을떄. 앞장에서 기술한것처럼, 만일 session key 값을 이용해서 어떤 정보가 변경이 되었다면 우리는 이에 대해 염려 할 필요가 없습니다.예를 들자면 : </p> + +<pre class="brush: python"># This is detected as an update to the session, so session data is saved. +request.session['my_car'] = 'mini'</pre> + +<p>만일 당신이 session data 안에 있는 어떤 정보를 수정 했다면 장고는 여러분이 수정한걸 알아채지 못합니다. (예를 들어, 만일 "my_car" 안의 "wheels" 정보를 수정 했다면 ). 이경우 명시적으로 그 session 이 수정 되었다고 아래의 코드처럼 표현해 주어야 합니다.</p> + +<pre class="brush: python"># Session object not directly modified, only data within the session. Session changes not saved! +request.session['my_car']['wheels'] = 'alloy' + +# Set session as modified to force data updates/cookie to be saved. +<code>request.session.modified = True</code> +</pre> + +<div class="note"> +<p><strong>Note</strong>: You can change the behavior so the site will update the database/send cookie on every request by adding <code>SESSION_SAVE_EVERY_REQUEST = True</code> into your project settings (<strong>locallibrary/locallibrary/settings.py</strong>).</p> +</div> + +<h2 id="간단한_예제_—_방문자수_받아오기">간단한 예제 — 방문자수 받아오기</h2> + +<p>간단한 실제 예제로서, 우리는 현재 유저가 LocalLibrary 홈페이지에 몇 번이나 방문했는지 알려주도록 업데이트할 것입니다. <strong>/locallibrary/catalog/views.py</strong> 을 열고 밑에 굵게 표시된 부분을 추가해서 바꿔봅시다. </p> + +<pre class="brush: python">def index(request): + ... + + num_authors = Author.objects.count() # The 'all()' is implied by default. + +<strong> # Number of visits to this view, as counted in the session variable. + num_visits = request.session.get('num_visits', 0) + request.session['num_visits'] = num_visits + 1</strong> + +<strong> context = { + 'num_books': num_books, + 'num_instances': num_instances, + 'num_instances_available': num_instances_available, + 'num_authors': num_authors, + 'num_visits': num_visits, + }</strong> + + # Render the HTML template index.html with the data in the context variable. + return render(request, 'index.html', context=context)</pre> + +<p>먼저 <code>'num_visits'</code> 세션 키 값을 가져오도록 합니다, 그리고 만약 전에 방문한적이 없다면 0이 되도록 합니다. 매번 요청받을 때 마다, 값을 증가시키고 세션에 값을 저장합니다 (유저의 다음 방문을 위해서요). context 변수를 통해 template에 <code>num_visits</code> 변수가 전달됩니다.</p> + +<div class="note"> +<p><strong>Note</strong>: 이 지점에서 우리는 브라우저가 쿠키를 지원하는 지 그렇지 않은지 테스트할 수도 있습니다(예제로서 <a href="https://docs.djangoproject.com/en/2.0/topics/http/sessions/">How to use sessions</a> 를 보도록하십시오). 또한 쿠키를 지원하는 지와는 별개로 UI를 디자인할 것입니다. </p> +</div> + +<p>메인 HTML template(<strong>/locallibrary/catalog/templates/index.html</strong>) "Dynamic content" 섹션 밑 부분에 context 변수가 보일 수 있도록 밑에 보이는 굵은 선으로 표시된 코드를 추가해주세요:</p> + +<pre class="brush: html"><h2>Dynamic content</h2> + +<p>The library has the following record counts:</p> +<ul> + <li><strong>Books:</strong> \{{ num_books }}</li> + <li><strong>Copies:</strong> \{{ num_instances }}</li> + <li><strong>Copies available:</strong> \{{ num_instances_available }}</li> + <li><strong>Authors:</strong> \{{ num_authors }}</li> +</ul> + +<strong><p>You have visited this page \{{ num_visits }}{% if num_visits == 1 %} time{% else %} times{% endif %}.</p></strong> +</pre> + +<p>바뀐 것을 저장해주시고 테스트 서버를 재시작해주세요. 페이지를 새로고침할 때 마다, 숫자가 업데이트되는 것을 보실 수 있을겁니다.</p> + +<ul> +</ul> + +<h2 id="요약">요약</h2> + +<p>익명 유저와의 상호작용을 증대하기 위해 세션을 이용하는 것이 얼마나 쉬운일인지 알 수 있었습니다. </p> + +<p>다음 장에서는, 인증과 권한부여(허가)에 관한 프레임워크를 설명할 것입니다. 그리고 유저 계정을 어떻게 지원할 수 있는지를 보도록 하죠. </p> + +<h2 id="See_also">See also</h2> + +<ul> + <li><a href="https://docs.djangoproject.com/en/2.0/topics/http/sessions/">How to use sessions</a> (Django docs)</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Django/Generic_views", "Learn/Server-side/Django/Authentication", "Learn/Server-side/Django")}}</p> + +<p> </p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Server-side/Django/Introduction">Django introduction</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/development_environment">Setting up a Django development environment</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Django Tutorial: The Local Library website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django Tutorial Part 2: Creating a skeleton website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Models">Django Tutorial Part 3: Using models</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Admin_site">Django Tutorial Part 4: Django admin site</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django Tutorial Part 5: Creating our home page</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Generic_views">Django Tutorial Part 6: Generic list and detail views</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Sessions">Django Tutorial Part 7: Sessions framework</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Authentication">Django Tutorial Part 8: User authentication and permissions</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Forms">Django Tutorial Part 9: Working with forms</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Testing">Django Tutorial Part 10: Testing a Django web application</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Django Tutorial Part 11: Deploying Django to production</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/web_application_security">Django web application security</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></li> +</ul> + +<p> </p> diff --git a/files/ko/learn/server-side/django/skeleton_website/index.html b/files/ko/learn/server-side/django/skeleton_website/index.html new file mode 100644 index 0000000000..b514a6ee61 --- /dev/null +++ b/files/ko/learn/server-side/django/skeleton_website/index.html @@ -0,0 +1,398 @@ +--- +title: '장고 튜토리얼 강좌 2 : 뼈대 사이트 만들기' +slug: Learn/Server-side/Django/skeleton_website +tags: + - 가이드 + - 입문서 + - 장고 + - 초심자 + - 튜토리얼 +translation_of: Learn/Server-side/Django/skeleton_website +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Django/Tutorial_local_library_website", "Learn/Server-side/Django/Models", "Learn/Server-side/Django")}}</div> + +<p class="summary"><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">장고 튜트리얼</a>의 두 번째 기사에서는 웹 사이트 프로젝트의 기본 뼈대(skeleton)를 만들고, 사이트의 특성에 맞춰 설정, 경로, 모델, 뷰 및 템플릿을 다루는 방법을 보여줍니다. </p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">사전 준비:</th> + <td><a href="/en-US/docs/Learn/Server-side/Django/development_environment">장고 개발 환경을 설치하세요. (Set up a Django development environment.)</a> <a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">장고 튜트리얼</a>을 복습하세요.</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>당신만의 새로운 웹사이트 프로젝트를 시작하기 위해 장고의 도구들을 사용할 수 있는 능력 기르기.</td> + </tr> + </tbody> +</table> + +<h2 id="개요">개요</h2> + +<p>이 글은 웹사이트의 "뼈대"를 생성하는 법을 보여줍니다. 그리고 이 사이트는 사이트에 특화된 설정, 경로, 모델, 뷰, 템플릿 등을 작성할 수 있습니다. (이후 글에서 이것들에 관해 다루겠습니다)</p> + +<p>과정은 직관적입니다:</p> + +<ol> + <li><span style="line-height: 1.5;">프로젝트 폴더, 기본적인 파일 템플릿과 프로젝트 관리 스크립트(</span><strong style="line-height: 1.5;">manage.py</strong><span style="line-height: 1.5;">)를 만들기 위해서 </span><code style="font-style: normal; font-weight: normal; line-height: 1.5;">django-admin</code><span style="line-height: 1.5;">을 사용합니다.</span></li> + <li><span style="line-height: 1.5;">하나 또는 그 이상의 애플리케이션을 만들기 위해서 </span><strong style="line-height: 1.5;">manage.py</strong><span style="line-height: 1.5;">를 사용합니다.</span> + <div class="note"> + <p><strong>Note</strong>: 하나의 웹사이트는 하나 또는 그 이상의 섹션으로 구성될 수 있습니다. (예를 들어 main site, blog, wiki, downloads area 등). 장고는 필요할 때에 다른 프로젝트에서 재사용이 가능할 수 있게 , 이 요소들을 분리된 어플리케이션으로 개발하는 것을 추천합니다.</p> + </div> + </li> + <li><span style="line-height: 1.5;">프로젝트에 포함시키기 위해 새 어플리케이션들을 등록(register)합니다. </span></li> + <li><span style="line-height: 1.5;">각 어플리케이션에 대해 url/mapper를 연결(hook up)합니다.</span></li> +</ol> + +<p><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Local Library website</a> 용으로 웹사이트 폴더와 프로젝트 폴더는 locallibrary라고 이름지어질 것입니다. 그리고 catalog라는 단 하나의 어플리케이션을 가질 겁니다. 그러므로 최상위 폴더 구조는 아래와 같습니다:</p> + +<pre class="brush: bash notranslate"><em>locallibrary/ # Website folder</em> + <strong>manage.py </strong># Script to run Django tools for this project (created using django-admin) + <em>locallibrary/ # Website/project folder </em>(created using django-admin) + <em>catalog/ # Application folder </em>(created using manage.py) +</pre> + +<p><span style="line-height: 1.5;">다음 섹션에서는 프로세스 단계를 자세히 설명하고 변화를 테스트할 수 있는 방법을 설명합니다. 글의 마지막에서 당신이 이 단계에서 수행해야 하는 몇 가지 다른 사이트 전체 설정에 관해 논의합니다.</span></p> + +<h2 id="프로젝트_만들기">프로젝트 만들기</h2> + +<p>먼저 명령 프롬프트 또는 터미널을 열어서, 당신이 <a href="/en-US/docs/Learn/Server-side/Django/development_environment#Using_a_virtual_environment">virtual environment</a> 안에 있는지 확인하고, 어디에 당신의 <span style="line-height: 1.5;">장고 앱을 (당신의 '문서'와 같이 찾기 쉬운 어딘가로 하세요) 저장하기 원하는지 탐색합니다. 그리고 당신의 새로운 웹사이트 폴더를 만드세요 (이 예제에서는: </span><em>locallibrary</em>). 그리고 cd 명령어를 사용하여 해당 폴더로 들어가세요:</p> + +<pre class="brush: bash notranslate">mkdir locallibrary +cd locallibrary +</pre> + +<p>다음과 같이 <code>django-admin startproject</code> 명령을 사용하여 새로운 프로젝트를 만들고, 그 폴더 안으로 들어가세요. (변역자주: 실제 해보니 위의 문장은 하지 말아야 합니다. 하나의 parent folder 가 더 만들어집니다. 즉, locallibrary-locallibrary-locallibrary )</p> + +<pre class="brush: bash notranslate">django-admin startproject locallibrary +cd locallibrary</pre> + +<p><code>django-admin</code> 도구가 아래와 같이 폴더/파일 구조를 생성합니다. (번역자주: 윈도우 환경에서는 <code>tree /f locallibrary_path</code> 명령으로 구조를 확인할 수 있습니다.)</p> + +<pre class="brush: bash notranslate"><em>locallibrary/</em> + manage.py + <em>locallibrary/</em> + __init__.py + settings.py + urls.py + wsgi.py</pre> + +<p>locallibrary 프로젝트의 하위 폴더는 웹사이트의 시작점입니다:</p> + +<ul> + <li><strong>__init__.py</strong>는 빈 파일입니다. 이 파일은 파이썬에게 이 디렉토리를 하나의 파이썬 패키지로 다루도록 지시합니다.</li> + <li><strong>settings.py</strong>는 웹사이트의 모든 설정을 포함하고 있습니다. 이 파일에는 우리가 만드는 모든 어플리케이션, 정적 파일의 위치, 데이터베이스 세부 설정 등을 등록합니다. </li> + <li><strong>urls.py</strong>는 사이트의 URL과 뷰의 연결을 지정해줍니다. 여기에는 모든 URL 매핑 코드가 포함될 수 있지만, 특정한 어플리케이션에 매핑의 일부를 할당해주는 것이 일반적입니다<span style="line-height: 1.5;">. </span></li> + <li><strong style="line-height: 1.5;">wsgi.py</strong><span style="line-height: 1.5;">는 당신의 장고 어플리케이션이 웹서버와 연결 및 소통하는 것을 돕습니다. 당신은 이것을 표준 형식(boilerplate)으로 다뤄도 무방합니다.</span></li> + <li><strong>asgi.py</strong> is a standard for Python asynchronous web apps and servers to communicate with each other and positioned as an asynchronous successor to WSGI, where WSGI provided a standard for synchronous Python apps, ASGI provides one for both asynchronous and synchronous apps, with a WSGI backward-compatibility implementation and multiple servers and application frameworks.</li> +</ul> + +<p><strong>manage.py</strong>는 어플리케이션을 생성하고, 데이터베이스와 작업하고, 그리고 개발 웹 서버를 시작하기 위해 사용됩니다. </p> + +<h2 id="catalog_application_만들기">catalog application 만들기</h2> + +<p>다음으로, locallibrary 프로젝트 안에 생성될 catalog 어플리케이션을 만들기 위해 아래 명령어를 실행하세요. 이것은 프로젝트의 <strong>manage.py</strong>와 같은 폴더 안에서 실행되어야 합니다.</p> + +<pre class="brush: bash notranslate">python3 manage.py startapp catalog</pre> + +<div class="note"> +<p><strong>주의 </strong>: 위 명령어는 리눅스/macOS X를 위한 명령어입니다. 윈도우에서의 명령어는 다음과 같습니다. <code>py -3 manage.py startapp catalog</code></p> + +<p>만약 윈도우에서 작업한다면, 이 튜트리얼 전체에서 <code>python3</code>를 <code>py -3</code>로 바꾸십시오.</p> + +<p>만약 파이썬 3.7.0 이상을 사용한다면 <code>py manage.py startapp catalog</code>를 사용하면 됩니다.</p> +</div> + +<p>이 도구는 새로운 폴더를 생성하고 폴더를 어플리케이션의 파일들로 채웁니다(아래에 굵게 표시). 대부분의 파일들은 그것의 목적에서 따온 이름을 갖고 있습니다. 예를들어, 뷰는 <strong>views.py</strong>에, 모델은 <strong>models.py</strong>에, 테스트는 <strong>tests.py</strong>에, 관리자 사이트 설정은 <strong>admin.py</strong>에, 어플리케이션 등록(registration)은 <strong>apps.py</strong>에 있습니다. 그리고 관련 객체(object)에 대한 작업을 위한 최소한의 표준 코드를 포함합니다.</p> + +<p>이제 업데이트된 프로젝트 디렉토리는 다음과 같아야 합니다. </p> + +<pre class="brush: bash notranslate"><em>locallibrary/</em> + manage.py + <em>locallibrary/ +</em><strong> <em>catalog/</em> + admin.py + apps.py + models.py + tests.py + views.py + __init__.py + <em>migrations/</em></strong> +</pre> + +<p> 추가로 다음을 갖게 됐습니다:</p> + +<ul> + <li><strong>migrations 폴더</strong> — 모델을 수정할 때 마다 자동으로 데이터베이스를 업데이트하는 것을 가능하게 해 줄 마이그레이션 파일들을 저장할 폴더 </li> + <li><strong>__init__.py</strong> — 장고/파이썬이 폴더를 <a href="https://docs.python.org/3/tutorial/modules.html#packages">파이썬 패키지</a>로 인식하게 할 빈 파일입니다. 또한 프로젝트의 다른 부분에서 객체(object)를 사용할 수 있게 합니다.</li> +</ul> + +<div class="note"> +<p><strong>주의 </strong>: 위의 파일 리스트에서 뭔가 부족한게 있다는 것을 알아챘나요? 뷰와 모델 관련 파일은 있는 반면 URL 맵핑, 템플릿, 정적 파일(static file)과 연관된 파일이 없습니다. 그들을 어떻게 생성하는지에 관해서는 추후에 보여드리겠습니다 (이것들은 모든 웹사이트에서 필요하진 않지만 우리 프로젝트에서는 필요합니다).</p> +</div> + +<h2 id="catalog_application_등록하기">catalog application 등록하기</h2> + +<p>이제 어플리케이션이 생성되었으니 프로젝트에 등록(register)해야합니다. 도구가 실행될 때 프로젝트에 포함시키기 위해서 말이죠(예를 들어 모델을 데이터베이스에 추가할 때 처럼요). 어플리케이션들은 프로젝트 설정 안의 <code>INSTALLED_APPS</code> 리스트에 추가함으로써 등록할 수 있습니다. </p> + +<p>프로젝트의 설정 파일(<strong>locallibrary/locallibrary/settings.py</strong>)을 열고 <code>INSTALLED_APPS</code> 리스트의 정의 부분을 찾으세요. 그리고 그 리스트 제일 아래에 다음과 같이 기입해 주세요.</p> + +<pre class="brush: bash notranslate">INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', +<strong> 'catalog.apps.CatalogConfig', </strong> +]</pre> + +<p>새로운 행은 어플리케이션 구성 객체(application configuration object)(<code>CatalogConfig</code>)를 지정하게 됩니다. 이것은 어플리케이션을 생성할 때 <strong>/locallibrary/catalog/apps.py</strong> 안에 생성됩니다.</p> + +<div class="note"> +<p><strong>주의</strong>: 설정 파일에 이미 많은 <code>INSTALLED_APPS</code> 항목과 <code>MIDDLEWARE</code> 항목이 있음을 알 수 있습니다. 이를 통해 <a href="/en-US/docs/Learn/Server-side/Django/Admin_site">장고 관리 사이트</a>를 지원할 수 있으며 결과적으로 세션, 인증 등을 포함한 많은 기능이 사용됩니다.</p> +</div> + +<h2 id="데이터베이스_설정">데이터베이스 설정</h2> + +<p>이제 보통 프로젝트에 사용할 데이터베이스를 지정하는 시점입니다— 가능한 한 개발과 결과물에 동일한 데이터베이스를 사용하여 사소한 동작 차이를 방지해야 합니다. <a href="https://docs.djangoproject.com/en/2.0/ref/settings/#databases">Databases에 대한 장고 문서</a>에서 가능한 다른 옵션을 확인할 수 있습니다. </p> + +<p>이 예제에서는 SQLite 데이터베이스를 사용합니다. 데모 데이터베이스에서 많은 동시 접속을 예상하지 않고, 설정에 추가적인 작업이 필요없기 때문입니다. 이 데이터베이스가 어떻게 설정되어 있는지 <strong>settings.py</strong>에서 확인할 수 있습니다.</p> + +<pre class="brush: python notranslate">DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), + } +} +</pre> + +<p>우리는 SQLite를 사용하기 때문에 여기서 다른 어떤 작업도 할 필요가 없습니다. 다음으로 가죠!</p> + +<h2 id="프로젝트의_다른_설정">프로젝트의 다른 설정</h2> + +<p><strong>settings.py</strong> 파일은 다른 많은 설정을 조정하는 데에 사용됩니다. 그러나 지금은 <a href="https://docs.djangoproject.com/en/2.0/ref/settings/#std:setting-TIME_ZONE">TIME_ZONE</a> 만 바꿔 봅시다— 이 부분은 표준화된 <a href="https://en.wikipedia.org/wiki/List_of_tz_database_time_zones">List of tz database time zones</a>과 일치되는 문자열을 사용해야 합니다 (테이블의 TZ 열의 값들을 참고하세요). <code>TIME_ZONE</code> 값을 당신의 타임존에 알맞은 문자열로 바꾸세요. (역자주: 한국은 <code>'Asia/Seoul'</code>로 설정)</p> + +<pre class="brush: python notranslate">TIME_ZONE = 'Europe/London'</pre> + +<p>지금은 바꾸지 않지만 알아둬야 할 두 가지 설정이 있습니다:</p> + +<ul> + <li><code>SECRET_KEY</code> : 이것은 장고의 웹사이트 보안 전략의 일부로 사용되는 비밀키입니다. 만약 이 코드를 개발 과정에서 보호하지 않는다면 제품화(production) 과정에서 다른 코드(아마 환경변수나 파일에서 읽어오는)를 사용해야 할 것입니다. </li> + <li><code>DEBUG</code> : 이것은 에러가 발생했을 때 HTTP 상태코드 응답 대신 디버깅 로그가 표시되게 합니다. 디버깅 정보는 공격자에게 유용하기 때문에 제품화된(production) 환경에서는 <code>False</code> 로 설정해야 합니다. 하지만, 지금은 <code>True</code>로 설정합니다.</li> +</ul> + +<h2 id="URL_맵퍼_연결">URL 맵퍼 연결</h2> + +<p>웹사이트는 프로젝트 폴더 안의 URL 맵퍼 파일(<strong>urls.py</strong>)과 같이 생성됩니다. <strong>urls.py</strong>를 통해 모든 URL 맵핑을 관리할 수 있지만, 연관된 어플리케이션에 따라 매핑을 다르게 하는 것이 일반적입니다.</p> + +<p><strong> locallibrary/locallibrary/urls.py</strong> 파일을 열어서 URL 맵퍼를 사용하는 몇 가지 방법을 설명하는 문서를 살펴보세요. </p> + +<pre class="brush: python notranslate">"""locallibrary URL Configuration + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/2.0/topics/http/urls/ +예제: +Function views 일 경우 + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views 일 경우 + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +다른 참조할 URL FILE 들을 포함시켜야 하는경우 + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" +from django.contrib import admin +from django.urls import path + +urlpatterns = [ + path('admin/', admin.site.urls), +] +</pre> + +<p>URL 맵핑은 <code>urlpatterns</code> 변수를 통해 관리되는데, 이 변수는 <code>path()</code> 함수의 파이썬 <code>list</code> 타입입니다. 각각의 <code>path()</code> 함수는 패턴이 일치할 때 표시될 뷰에 URL 패턴을 연결하거나, 다른 URL 패턴 테스트 코드 목록에 연결합니다(이 두 번째 경우에서 패턴은 대상 모듈에서 정의된 패턴의 "기본 URL"이 됩니다). <code>urlpatterns</code> 리스트는 맨 처음에 관리자 어플리케이션의 고유한 URL 맵핑 정의를 갖고 있는 <code>admin.site.urls</code> 모듈에 <code>admin/</code> 패턴을 가지고 있는 모든 URL을 매핑하는 단일 함수를 정의합니다.</p> + +<div class="note"> +<p><strong>주의</strong>: <code>path()</code> 속의 경로는 일치시킬 URL 패턴을 정의하는 문자열입니다. 이 문자열은 명명된(named) 변수를 꺽쇠 괄호(<code>< ></code>) 안에 포함할 수 있습니다. (예시: <code>'catalog/<id>/'</code>) 이 패턴은 URL을 <strong>/catalog/</strong><em>any_chars</em><strong>/</strong> 처럼 일치시키고 <em>any_chars</em>를 뷰에 매개 변수 이름이 <code>id</code> 인 문자열로 전달합니다. 경로(path) 함수(method)와 경로(route) 패턴에 대해서는 추후에 더 논의하겠습니다.</p> +</div> + +<p><code>urlpatterns</code> 리스트에 새로운 리스트 항목을 추가하기 위해서 아래 코드를 파일의 마지막에 추가하세요. 이 새로운 항목은 요청(request)을 모듈 <code>catalog.urls</code>(관련 URL <strong>/catalog/urls.py</strong>가 있는 파일)에 <code>catalog/</code> 패턴과 함께 전달하는 <code>path()</code>를 포함합니다. (번역자주: 만일 <code>www.xxxx.com/catalog</code>로 시작되는 요청이 들어 오면 <code>catalog/urls.py</code>를 참조해서 맵핑하겠다는 의미)</p> + +<pre class="brush: python notranslate"># Use include() to add paths from the catalog application +from django.conf.urls import include +from django.urls import path + +urlpatterns += [ + path('catalog/', include('catalog.urls')), +] +</pre> + +<p>이제 사이트의 루트 URL(즉, <code>127.0.0.1:8000</code>)을 <code>127.0.0.1:8000/catalog/</code>로 리다이렉트 하도록 합시다. 이것이 우리가 이 프로젝트에서 사용하는 유일한 어플리케이션입니다. 이것을 하기 위해서는 특별한 뷰 함수(<code>RedirectView</code>)를 사용할 겁니다. 이 함수는 <code>path()</code>에서 지정된 URL 패턴이 일치할 때(위의 경우에선 루트 URL이죠) 첫 번째 인자를 (<code>/catalog/</code>)로 리다이렉트할 새로운 상대 URL로 간주합니다.</p> + +<p>파일의 하단에 아래 코드를 다시 추가하세요:</p> + +<pre class="brush: python notranslate">#Add URL maps to redirect the base URL to our application +from django.views.generic import RedirectView +</pre> + +<pre class="notranslate"><code>urlpatterns += [ + path('', RedirectView.as_view(url='/catalog/', permanent=True)), +]</code></pre> + +<p><code>path()</code> 함수의 첫 번째 매개변수(parameter)를 비워 놓으면 <code>'/'</code>를 의미합니다. 만약 첫 번째 매개변수(parameter)를 <code>'/'</code>라고 작성한다면 개발 서버를 시작할 때 장고는 아래의 경고를 보여줄 겁니다.</p> + +<pre class="brush: python notranslate">System check identified some issues: + +WARNINGS: +?: (urls.W002) Your URL pattern '/' has a route beginning with a '/'. +Remove this slash as it is unnecessary. +If this pattern is targeted in an include(), ensure the include() pattern has a trailing '/'. +</pre> + +<p>장고는 기본적으로 CSS, JavaScript, 그리고 이미지와 같은 정적 파일을 제공하지 않지만, 이들은 사이트에 매우 유용할 수 있습니다. 최종적으로 이 URL 매퍼에 추가할 것은 개발 중에 정적 파일들을 제공하는 것을 가능하게 하는 아래 코드입니다. </p> + +<p>아래 코드를 파일의 하단에 추가하세요:</p> + +<pre class="notranslate"><code># Use static() to add url mapping to serve static files during development (only) +from django.conf import settings +from django.conf.urls.static import static + +urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)</code> +</pre> + +<div class="note"> +<p><strong> 주의</strong>: <code>urlpatterns</code> 리스트를 확장하는 여러 가지 방법들이 있습니다(위에서는 코드들을 명백하게 구분하기 위해서 간단히 <code>+=</code> 연산자를 사용해서 새로운 리스트 항목을 추가했습니다). 대신 원래의 리스트 정의 안에 새로운 패턴-맵을 추가하는 방법이 있습니다:</p> + +<pre class="brush: python notranslate">urlpatterns = [ + path('admin/', admin.site.urls), + path('catalog/', include('catalog.urls')), + path('', RedirectView.as_view(url='/catalog/', permanent=True)), +] + <code>static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)</code> +</pre> + +<p>추가적으로 임포트(import) 코드(<code>from django.urls import include</code>)를 그것을 사용하는 코드 바로 위에 선언했지만(무엇을 추가했는지 보기 쉽도록) 대개 import 문장은 파이썬 파일의 상단에 포함하는 것이 일반적입니다.</p> +</div> + +<p>마지막으로 <strong>urls.py</strong>라는 파일을 catalog 폴더 안에 생성하세요. 그리고 임포트된 (텅 빈(emptyt))<code>urlpatterns</code>를 정의하기 위해 아래 코드를 추가하세요. 어플리케이션을 만들면서 패턴들을 이곳에 추가할 것입니다. </p> + +<pre class="brush: python notranslate">from django.urls import path +from catalog import views + + +urlpatterns = [ + +] +</pre> + +<h2 id="Website_framework_테스트_하기">Website framework 테스트 하기</h2> + +<p>우리는 이 프로젝트의 뼈대(skeleton)를 만들었습니다. 웹사이트는 아직 아무것도 하지 않지만, 우리들이 여기까지 완성한 프로젝트가 오류 없이 돌아가는지 한번 실행해 볼 필요가 있습니다. </p> + +<p>그 전에 먼저 데이터베이스로의 마이그레이션(migration) 작업을 해야 합니다. 이것은 데이터베이스에 우리의 어플리케이션에 속한 모든 모델을 포함하도록 업데이트합니다(그리고 몇몇 빌드 경고의 원인을 제거합니다).</p> + +<h3 id="데이터베이스_마이그레이션migration_실행하기">데이터베이스 마이그레이션(migration) 실행하기</h3> + +<p>장고는 ORM(Object-Relational-Mapper : 객체-관계-매퍼)를 사용하여 장고 코드 안에 있는 모델 정의(객체)를 기본 데이터베이스에서 사용하는 데이터 구조(관계형 DB)에 매핑합니다. 모델의 정의를 바꿀 때 마다, 장고는 변화를 추적해서, 데이터베이스 안의 기본 데이터 구조가 모델과 일치하도록 자동적으로 이전(migrate)하는 스크립트를(<strong>/locallibrary/catalog/migrations/</strong>안에)생성할 수 있습니다.</p> + +<p>웹사이트를 생성할 때 장고는 사이트의 관리자 섹션(나중에 살펴볼)에서 사용할 여러 모델들을 자동으로 추가했습니다. 데이터베이스 안의 그 모델들을 위한 테이블들을 정의하기 위해 아래 명령어를 실행하세요(<strong>manage.py</strong>파일이 포함되어 있는 디렉토리에서 실행합니다). </p> + +<pre class="brush: bash notranslate">python3 manage.py makemigrations +python3 manage.py migrate +</pre> + +<div class="warning"> +<p><strong> 중요</strong>: 저장되어야 할 데이터의 구조에 영향을 미치는 방식으로 모델이 변경될 때마다 위의 명령어를 실행해야 합니다(모든 모델과 개별적인 필드의 추가와 제거를 포함하여).</p> +</div> + +<p><code>makemigrations</code> 명령어는 프로젝트에 설치된 모든 어플리케이션에 대한 migration을 생성합니다(하지만 적용하진 않습니다)(또한 그저 단일 프로젝트를 위한 migration을 실행하기 위해 어플리케이션 이름을 지정할 수 있습니다). 이것으로 migration이 적용되기 전에 코드를 점검할 기회를 가질 수 있습니다 — 당신이 장고 전문가가 되었을 땐 그것들을 조금 조정할 수도 있습니다!</p> + +<p><code>migrate</code> 명령어는 migration을 실제로 데이터베이스에 적용합니다(장고는 현재 데이터베이스에 어떤 것들이 추가되었는지 추적합니다).</p> + +<div class="note"> +<p><strong>주의</strong>: 덜 사용되는 migration 명령어에 대한 추가적인 정보는 <a href="https://docs.djangoproject.com/en/2.0/topics/migrations/">Migrations</a> (장고 문서)를 참고하세요.</p> +</div> + +<h3 id="웹사이트_실행하기">웹사이트 실행하기</h3> + +<p>개발 중에 먼저 개발 웹 서버를 사용해서 웹사이트를 서비스한 후 로컬 웹 브라우저에서 볼 수 있습니다. </p> + +<div class="note"> +<p><strong>주의</strong>: 개발용 웹 서버는 견고하거나 제품에 쓰일 만큼 충분하진 않지만, 개발 중에 편하고 빠른 테스트를 위해 장고 웹사이트를 실행할 수 있는 아주 쉬운 방법입니다. 기본적으로 사이트를 당신의 로컬 컴퓨터에(<code>http://127.0.0.1:8000/)</code>서비스 하지만, 네트워크에 있는 다른 컴퓨터를 지정해서 서비스하도록 할 수 있습니다. <a href="https://docs.djangoproject.com/en/2.0/ref/django-admin/#runserver">django-admin and manage.py: runserver</a> (장고 문서)에서 더 많은 정보를 확인하세요.</p> +</div> + +<p><strong>manage.py</strong>와 같은 디렉터리 안에 있는 <code>runserver</code> 명령어를 실행해 개발 웹 서버를 실행해 보세요.</p> + +<pre class="brush: bash notranslate">python3 manage.py runserver + + Performing system checks... + + System check identified no issues (0 silenced). + August 15, 2018 - 16:11:26 + Django version 2.1, using settings 'locallibrary.settings' + Starting development server at http://127.0.0.1:8000/ + Quit the server with CTRL-BREAK. +</pre> + +<p> 서버가 실행된다면 로컬 웹 브라우저에서 <code>http://127.0.0.1:8000/</code> 으로 이동하여 사이트를 볼 수 있습니다. 아래와 같은 사이트 에러 페이지가 뜰 겁니다:</p> + +<p><img alt="Django Debug page for Django 2.0" src="https://mdn.mozillademos.org/files/15729/django_404_debug_page.png"></p> + +<p>걱정 마세요! 예상된 에러 페이지입니다. 그 이유는 아직(사이트의 루트에 대한 URL을 가져올 때 리다이렉트되는) <code>catalogs.urls</code> 모듈 안에 정의된 page/url들이 없기 때문입니다. </p> + +<div class="note"> +<p><strong>주의</strong>: 위 페이지는 중요한 장고 기능을 보여줍니다— 자동화된 디버그 기록(logging)이죠. 에러 화면은 페이지를 찾을 수 없거나, 코드에서 에러가 발생했을 어떤 때라도 유용한 정보가 표시될 겁니다. 이 경우엔 (목록에 있는 대로) 우리가 제공한 URL과 일치하는 어떤 URL 패턴도 없다는 것을 볼 수 있습니다. 디버그 기록(logging)은 제품화되었을 (웹에 라이브로 사이트를 올려놓으면) 때는 꺼져 있을 겁니다. 정보는 더 적지만, 사용자 친화적인 페이지가 서비스되는 것이죠.</p> +</div> + +<p>이 지점에서 장고가 작동한다는 것을 알 수 있습니다! </p> + +<div class="note"> +<p><strong>주의</strong>: 어떤 때라도 중요한 변경이 있은 후에는 migration들을 재실행하고 사이트를 다시 테스트해야 합니다. 그렇게 오래 걸리진 않으니까 꼭 하세요!</p> +</div> + +<h2 id="도전_과제">도전 과제</h2> + +<p><strong>catalog/</strong> 디렉토리는 뷰, 모델, 그리고 어플리케이션의 다른 부분들을 위한 파일들을 포함하고 있습니다. 이 파일들을 열어 표준 코드(boilerplate)들을 점검해 보세요. </p> + +<p>위에서 본 것처럼, 관리자 사이트를 위한 URL 매핑은 이미 프로젝트의 <strong>urls.py</strong> 안에 추가되어 있습니다. 브라우저에서 관리자 영역으로 이동하여 어떤 일이 일어나는지 살펴보세요(위서 살펴본 매핑에서 올바른 URL을 추론할 수 있습니다).</p> + +<ul> +</ul> + +<h2 id="요약">요약</h2> + +<p>이제 urls, models, views, 그리고 templates으로 채울 수 있는 완벽한 뼈대 웹사이트 프로젝트를 만들었습니다.</p> + +<p><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Local Library website</a>를 위한 뼈대는 완성되어서 실행되고 있고, 이제는 이 웹사이트가 해야 할 일을 하게 만드는 코드를 작성할 시간입니다. </p> + +<h2 id="참고_항목">참고 항목</h2> + +<ul> + <li><a href="https://docs.djangoproject.com/en/2.0/intro/tutorial01/">Writing your first Django app - part 1</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.0/ref/applications/#configuring-applications">Applications</a> (Django Docs). 어플리케이션의 구성(configuring)에 관한 정보를 갖고 있습니다.</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Django/Tutorial_local_library_website", "Learn/Server-side/Django/Models", "Learn/Server-side/Django")}}</p> + + + +<h2 id="이_모듈_안에서">이 모듈 안에서</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Server-side/Django/Introduction">Django introduction</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/development_environment">Setting up a Django development environment</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Django Tutorial: The Local Library website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django Tutorial Part 2: Creating a skeleton website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Models">Django Tutorial Part 3: Using models</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Admin_site">Django Tutorial Part 4: Django admin site</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django Tutorial Part 5: Creating our home page</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Generic_views">Django Tutorial Part 6: Generic list and detail views</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Sessions">Django Tutorial Part 7: Sessions framework</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Authentication">Django Tutorial Part 8: User authentication and permissions</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Forms">Django Tutorial Part 9: Working with forms</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Testing">Django Tutorial Part 10: Testing a Django web application</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Django Tutorial Part 11: Deploying Django to production</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/web_application_security">Django web application security</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></li> +</ul> diff --git a/files/ko/learn/server-side/django/testing/index.html b/files/ko/learn/server-side/django/testing/index.html new file mode 100644 index 0000000000..d15550bd43 --- /dev/null +++ b/files/ko/learn/server-side/django/testing/index.html @@ -0,0 +1,933 @@ +--- +title: 'Django 튜토리얼 파트 10: Django 웹 어플리케이션 테스트하기' +slug: Learn/Server-side/Django/Testing +translation_of: Learn/Server-side/Django/Testing +--- +<h2 id="LearnSidebar">{{LearnSidebar}}</h2> + +<div>{{PreviousMenuNext("Learn/Server-side/Django/Forms", "Learn/Server-side/Django/Deployment", "Learn/Server-side/Django")}}</div> + +<p class="summary">웹사이트가 성장함에 따라 손으로 일일히 테스트하는 것은 점점 더 어려워진다. 테스트 할 내용이 늘어날 뿐만 아니라, 컴포넌트간의 상호작용도 복잡해지고, 한 쪽의 작은 수정이 다른쪽에 큰 영향을 줄수 있기 때문에, 모든것이 잘 동작할 수 있도록 더 많은 수정이 필요해지며, 그렇게 추가된 수정이 새로운 에러를 유발하지 않도록 확인되어야 한다. 이러한 문제들의 해결책중 하나는, 쉽고 안정적으로 수정사항이 발생할 때마다 실행되는 자동화된 테스트를 작성하는 것이다. 이 튜토리얼은 Django의 테스트 프레임워크를 사용하여 당신의 웹 사이트에 대한 Unit Testing을 자동화하는 방법을 보여줄것이다. </p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">사전학습:</th> + <td>아래 파트를 포함하여 앞선 모든 튜토리얼 파트의 학습을 완료할 것. <a href="/en-US/docs/Learn/Server-side/Django/Forms">Django 튜토리얼 파트 9: 폼으로 작업하기</a>.</td> + </tr> + <tr> + <th scope="row">학습목표:</th> + <td>Django 기반 웹사이트의 Unit Test 작성방법 이해하기.</td> + </tr> + </tbody> +</table> + +<h2 id="개요">개요</h2> + +<p>이제까지 개발된 <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a> 의 현재 상태는 다음과 같다. 모든 book과 author의 목록, <code>Book</code> 과 <code>Author</code> 항목별 상세 뷰, <code>BookInstance</code> 갱신용 페이지, <code>Author</code> 항목의 생성,갱신,삭제를 위한 페이지( <a href="/en-US/docs/Learn/Server-side/Django/Forms">forms tutorial</a> 편의 도전과제도 완성 했다면 <code>Book</code> 편집 페이지도 포함)가 완성 되었다. 상대적으로 작은 이 사이트조차, 각 페이지가 기대한 대로 동작하는지 손으로 대강 체크하는 것만 해도 몇 분 정도는 걸린다. 사이트가 성장하면서 수정사항이 늘어날수록 적절하게 동작하는지 우리가 수동으로 체크해야 하는 양도 늘어날 수 밖에 없다. 손으로 직접 테스트 하는 방법을 계속 유지한다면, 결국은 대부분의 시간을 테스트에 사용하고 코드를 개선할 수 있는 시간은 거의 없어질 것이다. </p> + +<p>자동화된 테스트는 이러한 문제를 진짜로 해결할 수 있다! 명백한 이점은 수동 테스트보다는 훨신 빠르고, 훨씬 세부적인 내용까지도 테스트 할수 있으며, 매번 정확히 같은 기능을 테스트할 수 있다는 점(사람이 테스트한다면 결코 신뢰성있게 할 수 없는 부분!) 이다. 자동화 테스트는 빠르기 때문에 좀 더 정기적으로 실행할 수 있고, 테스트 실패시 코드가 기대대로 동작하지 않았던 부분을 정확히 지목할 수 있다.</p> + +<p>게다가, 자동화된 테스트는 당신의 코드의 첫번째 실전 고객으로 역할을 수행하여, 당신의 웹사이트가 어떻게 동작해야하는지 엄격하게 정의하고 문서화하도록 압력을 준다. 종종 이 내용이 당신이 작성하게될 코드 예제나 관련문서의 기초 자료가 된다. 이러한 이유 때문에, 어떤 소프트웨어 개발 프로세스는 테스트 정의와 구현으로 시작되어, 테스트가 요구하는 동작을 충족하도록 코드가 작성되기도 한다. ( 예를 들면, <a href="https://en.wikipedia.org/wiki/Test-driven_development">test-driven</a> 과 <a href="https://en.wikipedia.org/wiki/Behavior-driven_development">behaviour-driven</a> 개발론).</p> + +<p>이 튜토리얼은 , LocalLibrary 웹사이트에 몇가지 테스트를 추가하면서, Django에 대한 자동화된 테스트를 작성하는 방법을 보여준다.</p> + +<h3 id="Testing의_종류">Testing의 종류</h3> + +<p>테스트의 성격, 수준, 테스트의 종류및 테스트에 대한 접근방법은 수없이 많다. 가장 중요한 방법들은 다음과 같다. :</p> + +<dl> + <dt>Unit tests (유닛 테스트)</dt> + <dd>독립적인 콤포넌트의 (성능이 아닌) 기능적인 동작을 검증한다. 흔히 class나 function 레벨로 수행한다.</dd> + <dt>Regression tests ( 버그수정 확인 테스트 )</dt> + <dd>기존에 보고된 버그들이 재발하는지 테스트한다. 각 테스트는, 먼저 이전에 발생했던 버그가 수정되었는지 체크한 이후에, 버그 수정으로 인해 새롭게 발생되는 버그가 없는지 확인차 재수행하게 된다.</dd> + <dt>Integration tests ( 통합 테스트 )</dt> + <dd>유닛 테스트를 완료한 각각의 독립적인 콤포넌트들이 함께 결합되어 수행하는 동작을 검증한다. 통합 테스트는 콤포넌트간에 요구되는 상호작용을 검사하며, 각 콤포넌트의 내부적인 동작까지 검증할 필요는 없다. 이 테스트는 단지 전체 웹사이트에 걸쳐 각 콤포넌트가 결합하여 수행하는 동작을 대상으로 한다.</dd> +</dl> + +<div class="note"> +<p><strong>참고사항 : </strong>이외의 일반적인 테스트의 종류는 다음과 같다. 블랙박스, 화이트 박스, 수동, 자동, 카나리아, 스모크, 적합성 평가(conformance), 인수(acceptance), 기능성, 시스템, 성능, 로드, 스트레스 테스트등. 더 자세한 정보는 위의 키워드로 검색 바람.</p> +</div> + +<h3 id="Django가_testing을_위해_제공하는_것은">Django가 testing을 위해 제공하는 것은?</h3> + +<p>웹사이트를 테스트하는 것은 복잡한 작업입니다. 왜냐하면 이것이 HTTP 레벨의 리퀘스트 핸들링, 쿼리모델들, 폼 인증과 처리 그리고 템플릿 렌더링과 같은 여러 로직 레이어로 만들어졌기 때문입니다.</p> + +<p>Django는 파이선 표준 라이브러리 unittest로 만들어진 작은 클라스계층의 테스트 프레임워크를 제공합니다. 그 이름과 다르게 이 테스트 프레임워크는 유닛테스트와 통합테스트 모두에게 적당합니다. 이 Django 프레임워크는 웹과 Django의 독특한 특징을 테스트하는 것을 돕기 위한 API메소드와 도구들을 추가합니다. 이것들은 당신이 리퀘스트를 시험하고, 시험 데이터를 삽입하고 그리고 당신의 애플리케이션의 결과물을 검사할 수 있게 합니다. Django는 또한 다른 테스트 프레임워크들을 사용하기 위한 API (LiveServerTestCase)와 도구들을 제공합니다. 예를 들면 당신은 사용자가 생중계 브라우저와 소통하는 것을 시뮬레이션하는 유명한 Selenium 프레임워크와 통합할 수 있습니다.</p> + +<p>테스트를 작성하기 위해서는 Django(또는 unittest) 테스트기반 클라스들(<a href="https://docs.djangoproject.com/en/2.1/topics/testing/tools/#simpletestcase">SimpleTestCase</a>, <a href="https://docs.djangoproject.com/en/2.1/topics/testing/tools/#transactiontestcase">TransactionTestCase</a>, <a href="https://docs.djangoproject.com/en/2.1/topics/testing/tools/#testcase">TestCase</a>, <a href="https://docs.djangoproject.com/en/2.1/topics/testing/tools/#liveservertestcase">LiveServerTestCase</a>)로부터 어떤 것을 가져오고 그리고 그 다음에 특별한 기능이 기대했던대로 작동하는지 체크하기 위한 분리된 메소드들을 작성합니다. (테스트들은 그 표현식의 결과가 True 또는 False 값인지 또는 그 두 값들이 동등한지 등을 테스트하기 위해 "assert" 메소드를 사용합니다) 당신이 테스트를 시작하면, 그 프레임워크는 당신의 가져온 클라스들안에서 선택된 테스트 메소드들을 실행합니다. 아래에 보이는 것과 같이, 그 테스트 메소드들은 클라스에서 정의된 보통의 셋업 그리고/또는 tear-down 방식을 가지고 독립적으로 실행됩니다.</p> + +<pre class="brush: python notranslate">class YourTestClass(TestCase): + def setUp(self): + # Setup run before every test method. + pass + + def tearDown(self): + # Clean up run after every test method. + pass + + def test_something_that_will_pass(self): + self.assertFalse(False) + + def test_something_that_will_fail(self): + self.assertTrue(False) +</pre> + +<p>대부분의 테스트들을 위한 최선의 기본 클라스는 <a href="https://docs.djangoproject.com/en/2.0/topics/testing/tools/#testcase">django.test.TestCase</a> 입니다. 이 테스트 클라스는 이것이 실행되기 전에 하나의 깨끗한 데이터베이스를 생성하고, 그리고 이 자체의 트랜젝션에서 모든 테스트를 실행합니다. 이 클라스는 자체의 테스트 클라이언트를 갖고있는데, 이것은 당신이 view 레벨에서 그 코드가 사용자와 상호작용하는 것을 시뮬레이션할 수 있게 합니다. 아래 섹션에서는 이 <a href="https://docs.djangoproject.com/en/2.0/topics/testing/tools/#testcase">TestCase</a> 기본 클라스를 이용하여 유닛테스트들에 집중할 것입니다. </p> + +<div class="note"> +<p><strong>Note:</strong> 이<a href="https://docs.djangoproject.com/en/2.0/topics/testing/tools/#testcase">django.test.TestCase</a> 클라스는 매우 편리합니다. 그러나 어떤 테스트들은 그들이 필요로하는 것보다 느려지는 결과가 올 수 있습니다(모든 테스트들이 그들 자체의 데이터베이스나 또는 view 상호작용의 셋업이 필요한 것은 아닙니다) 한번 당신이 이 클라스를 통해서 무엇을 할 수 있는지 익숙해진다면, 당신은 더 심플한 테스트 클라스들을 가지고 당신의 몇몇 테스트들을 대체하게 될 것입니다.</p> +</div> + +<h3 id="무엇을_테스트해야_하는가">무엇을 테스트해야 하는가?</h3> + +<p>Python 또는 Django의 일부분으로서 제공되는 라이브러리들 또는 기능들을 제외한 당신 코드의 모든 면을 테스트해야합니다. </p> + +<p>예를 들면, 아래에 정의된 Author 모델을 가정합니다. 당신은 first_name과 last_name이 데이터베이스 CharField로서 적당하게 저장됐는지에 대해 명시적으로 테스트할 필요가 없습니다. 왜냐하면, 그것은 Django에 의해 정의된 것이기 때문입니다. (물론 사실은 당신이 개발하는 중에 이 기능들을 필연적으로 테스트했음에도 불구하고요) 또한 date_of_birth가 날짜 필드에 적합한 값을 갖었는지 테스트하는 것도 필요없습니다. 왜냐하면 그렇게 하는 것은 Django에서 다시한번 더 실행하는 것이 되니까요. </p> + +<p>그러나 당신은 그 레이블들(<em>First name, Last name, Date of birth, Died</em>)로 사용된 텍스트 그리고 그 텍스트(100 chars)을 위해 할당한 그 필드의 크기를 확인해야 합니다. 왜냐하면 이것들은 당신이 디자인한 것이고 추후에 깨지거나 변경될 수 있는 것이기 때문입니다.</p> + +<pre class="brush: python notranslate">class Author(models.Model): + first_name = models.CharField(max_length=100) + last_name = models.CharField(max_length=100) + date_of_birth = models.DateField(null=True, blank=True) + date_of_death = models.DateField('Died', null=True, blank=True) + + def get_absolute_url(self): + return reverse('author-detail', args=[str(self.id)]) + + def __str__(self): + return f'{self.last_name}, {self.first_name}'</pre> + +<p>단순히, 당신은 당신의 요구에 따라 만들어지 메소드들 <code style="font-style: normal; font-weight: normal;">get_absolute_url()</code> 과 <code style="font-style: normal; font-weight: normal;">__str__()</code> 이 원래 요구된 대로 작동하는지 체크해야합니다. 왜냐하면 이것들은 당신이 만들어낸 코드/비즈니스 로직이기 때문입니다. <code style="font-style: normal; font-weight: normal;">get_absolute_url()</code>의 경우에 있어서는 Django의 reverse() 메소드는 적당하게 작동되었다고 신뢰할 수 있습니다, 그래서 당신이 테스트해야 하는 것은 실제로 정의되어온 관련된 view 입니다. </p> + +<div class="note"> +<p><strong>Note:</strong> 영특한 독자들은 date of birth와 date of death를 합리적인 값으로 제한해야 한다고 적어야 하고, 그리고 death는 birth보다 뒤에 왔는지를 체크해야 한다고 할 것입니다. Django에 있어서 이 제약은 당신의 폼클라스에 추가될 것입니다(당신이 그 필드들의 이러한 모습을 모델 레벨이 아니라 오직 폼 레벨에서 사용될 수 있도록 인증을 정의할 수 있다고 할지라도 말입니다)</p> +</div> + +<p>이런 것들을 마음에 두고서 테스트를 정의하고 실행해봅시다.</p> + +<h2 id="테스트_구조_개요">테스트 구조 개요</h2> + +<p>무엇을 테스트 할 지 자세히 보기 전에, 간단히 어디서 그리고 어떻게 테스트가 정의되는지 대략 살펴 봅시다.</p> + +<p>장고는 유닛테스트의 모듈인 <a href="https://docs.python.org/3/library/unittest.html#unittest-test-discovery" title="(in Python v3.5)">built-in test discovery</a>을 사용하는데, 이는 현재 작업중인 디렉토리의 <strong>test*.py</strong>라는 패턴을 가진 모든 파일들을 체크합니다. 그 파일들의 이름을 적당하게 붙이는 한, 당신은 당신이 원하는 어떤 구조라도 이용할 수 있습니다. 우리는 당신의 테스트코드를 위한 한 모듈을 만들 것을 추천합니다. 그리고 모델들, 뷰들, 폼들 그리고 테스트가 필요한 어떤 다른 타입의 코드라도 각각을 분리하기를 바랍니다. 예를 들면:</p> + +<pre class="notranslate">catalog/ + /tests/ + __init__.py + test_models.py + test_forms.py + test_views.py +</pre> + +<p>당신의 LocalLibrary 프로젝트에서 위와 같은 구조의 파일을 만드십시오. __init__.py 파일은 비어있는 파일입니다.(이것은 Python에게 이 디렉토리가 패키지임을 알려줍니다) skeleton 테스트파일인 /catalog/tests.py를 복사하여 이름을 바꿔서 위의 세개의 테스트파일을 만드십시오.</p> + +<div class="note"> +<p><strong>Note:</strong> 이 skeleton 테스트파일 <strong>/catalog/tests.py 은 우리가 </strong><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django skeleton website</a> 를 만들었을 때 자동으로 생성됩니다. 당신의 테스트들을 여기에 모두 넣는 것도 괜찮습니다만, 당신이 적절하게 테스트를 해나가면 당신은 금방 매우 크고, 관리할 필요 없는 테스트파일로 끝나게 될 것입니다. </p> + +<p>이 skeleton 파일은 우리에게 필요하지 않으니 지우십시오.</p> +</div> + +<p><strong>/catalog/tests/test_models.py </strong>파일을 오픈하십시오. 이 파일은 아래와 같이 <code>django.test.TestCase </code>가 import 되었을 것입니다.</p> + +<pre class="brush: python notranslate">from django.test import TestCase + +# Create your tests here. +</pre> + +<p> 당신은 종종 특정한 기능을 테스트하기 위한 개별적인 메소드들을 가지고 당신이 테스트하기를 원하는 각각의 모델/뷰/폼을 위한 테스트 클라스를 추가할 것입니다. 또 다른 경우에는 당신은 그 사용사례의 다방면을 테스트하기 위한 개별적인 테스트기능을 가지고, 특별한 사용사례를 테스트하기 위한 별도의 클라스를 갖기를 원할 것입니다. (예를 들면, 실패한 사례들을 테스트하는 기능을 가지고 모델 필드가 적정하게 인증되었는지 테스트하는 한 클라스) 다시한번, 그 구조는 오직 당신 자신에게 달렸습니다. 그러나 당신이 일관되게 하는 것이 최선의 방법입니다. </p> + +<p>아래의 테스트 클라스를 파일 맨아랫부분에 추가하십시오. 이 클라스는 <code>TestCase</code>으로부터 이끌어내어서 어떻게 테스트케이스 클라스를 구축하는지 예시를 보여줍니다.</p> + +<pre class="brush: python notranslate">class YourTestClass(TestCase): + @classmethod + def setUpTestData(cls): + print("setUpTestData: Run once to set up non-modified data for all class methods.") + pass + + def setUp(self): + print("setUp: Run once for every test method to setup clean data.") + pass + + def test_false_is_false(self): + print("Method: test_false_is_false.") + self.assertFalse(False) + + def test_false_is_true(self): + print("Method: test_false_is_true.") + self.assertTrue(False) + + def test_one_plus_one_equals_two(self): + print("Method: test_one_plus_one_equals_two.") + self.assertEqual(1 + 1, 2)</pre> + +<p> 이 새로운 클래스는 테스트 전 준비를 위해 사용할 수 있는 메쏘드 두 개를 정의합니다. (예를 들면 테스트에 필요한 모델이나 객체를 생성해 놓을 수 있습니다):</p> + +<ul> + <li><code>setUpTestData()</code> 는 클래스 전체에서 사용되는 설정을 위해서 테스트 시작 때 딱 한 번만 실행됩니다. 테스트 메쏘드가 실행되면서 수정되거나 변경되지 않을 객체들을 이곳에서 생성할 수 있습니다.</li> + <li><code>setUp()</code> 은 각각의 테스트 메쏘드가 실행될 때마다 실행됩니다. 테스트 중 내용이 변경될 수 있는 객체를 이곳에서 생성할 수 있습니다 (모든 테스트 메쏘드는 방금 막 생성된 ("fresh") 오브젝트를 입력받게 됩니다).</li> +</ul> + +<div class="note"> +<p>테스트 클래스는 위 예제에서 사용하지 않은 <code>tearDown(</code>h 메소드를 가지고 있습니다. 이 메소드는 특히 데이터베이스 테스트에는 유용하지가 않은데 바로 베이스 클래스인 <code>TestCase</code> 가 데이터베이스 삭제(teardown) 을 처리해주기 때문입니다.</p> +</div> + +<p>아래에는 <code>Assert</code> 함수를 사용하여 조건이 참, 거짓 또는 동일한지 테스트하는 여러 가지 테스트 메서드가 있습니다 (<code>AssertTrue</code>, <code>AssertFalse</code>, <code>AssertEqual</code>). 조건이 예상대로 실행되지 않으면 테스트가 실패하고 콘솔에 오류를 보고합니다.</p> + +<div class="note"> +<p>일반적으로 위와 같이 테스트에 <strong>print()</strong> 함수를 포함하면 <strong>안</strong>됩니다. 여기서는 setup 함수들이 콘솔에서 호출되는 순서를 (다음 절에서) 볼 수 있도록 하기 위해 사용되었습니다.</p> +</div> + +<h2 id="어떻게_테스트를_작동시키는가">어떻게 테스트를 작동시키는가</h2> + +<p>모든 테스트를 실행하는 가장 쉬운 방법은 다음 명령을 사용하는 것입니다.</p> + +<pre class="brush: bash notranslate">python3 manage.py test</pre> + +<p>이 명령은 현재 경로에서 <strong>test*.py </strong>패턴을 만족하는 모든 파일을 찾은 후 이들 테스트를 적합한 베이스 클래스를 이용해서 실행합니다 (우리는 현재 여러 개의 테스트 파일을 가지고 있지만 <strong>/catalog/tests/test_models.py </strong>만이 실제 테스트를 포함하고 있습니다. 기본적으로 각각의 테스트는 실패 결과만을 보고하며, 마지막으로 테스트 결과 요약을 출력합니다.</p> + +<div class="note"> +<p>만약 <code>ValueError: Missing staticfiles manifest entry ...</code> 과 같은 에러를 마주칠 수 있습니다. 이런 에러는 보통 테스팅 도구가 기본적으로 collectstatic을 실행하지 않고, 당신의 앱이 이를 요구하는 storage 클래스를 사용하기 때문일 수 있습니다 (<a href="https://docs.djangoproject.com/en/2.0/ref/contrib/staticfiles/#django.contrib.staticfiles.storage.ManifestStaticFilesStorage.manifest_strict">manifest_strict</a> 에 더 자세한 정보가 적혀 있습니다). 이 문제를 해결할 수 있는 다양한 방법이 있지만 가장 간단한 방법은 테스트 실행 전에 collectstatic을 실행하는 것입니다.</p> + +<pre class="brush: bash notranslate">python3 manage.py collectstatic +</pre> +</div> + +<p><em>LocalLibrary</em>의 루트 디렉토리에서 테스트를 실행하세요. 당신은 아래와 같은 출력output을 볼 것입니다.</p> + +<pre class="brush: bash notranslate">> python3 manage.py test + +Creating test database for alias 'default'... +<strong>setUpTestData: Run once to set up non-modified data for all class methods. +setUp: Run once for every test method to setup clean data. +Method: test_false_is_false. +setUp: Run once for every test method to setup clean data. +Method: test_false_is_true. +setUp: Run once for every test method to setup clean data. +Method: test_one_plus_one_equals_two.</strong> +. +====================================================================== +FAIL: test_false_is_true (catalog.tests.tests_models.YourTestClass) +---------------------------------------------------------------------- +Traceback (most recent call last): + File "D:\Github\django_tmp\library_w_t_2\locallibrary\catalog\tests\tests_models.py", line 22, in test_false_is_true + self.assertTrue(False) +AssertionError: False is not true + +---------------------------------------------------------------------- +Ran 3 tests in 0.075s + +FAILED (failures=1) +Destroying test database for alias 'default'...</pre> + +<p>여기서 우리는 테스트 하나가 실패했음을 알 수 있으며, 실패한 함수와 실패한 이유를 정확히 볼 수 있습니다 (False가 True가 아니기 때문에 실패하는 것이 당연합니다).</p> + +<div class="note"> +<p><strong>팁</strong>: 우리는 위의 출력 결과를 통해서 객체와 메소드에 설명적인, 정보가 많은 이름을 사용하는 것이 테스트 결과를 이해하는데 도움이 된다는 것을 배울 수 있습니다.</p> +</div> + +<p><strong>굵게 </strong>표시된 텍스트는 보통은 테스트 결과에 출력되지 않습니다 (우리가 테스트에서 사용한 <code>print()</code> 함수가 출력한 것입니다). 이는 <code>setUpTestData()</code> 가 클래스 당 한 번, <code>setUp()</code> 이 메소드 당 한 번 실행되는 것을 보여줍니다.</p> + +<p>다음 섹션은 특정 테스트만 실행하는 방법과 테스트가 출력하는 정보를 조절하는 방법을 알려줍니다.</p> + +<h3 id="테스트에_대해_더_많은_정보를_출력하기">테스트에 대해 더 많은 정보를 출력하기</h3> + +<p>테스트 실행에 대한 자세한 정보를 얻으려면 verbosity를 조절할 수 있습니다. 예를 들어 테스트 실패와 더불어 성공 (그리고 테스트 데이터베이스 생성 과정에 대한 정보)를 나열하려면 다음과 같이 verbosity를 "2"로 설정할 수 있습니다.</p> + +<pre class="brush: bash notranslate">python3 manage.py test --verbosity 2</pre> + +<p>허용되는 verbosity levels 은 0, 1, 2, and 3, 이며 기본값은 "1" 입니다.</p> + +<h3 id="테스트의_일부만_실행하기">테스트의 일부만 실행하기</h3> + +<p>테스트 중 일부만 실행하려면 패키지, 모듈, <code>TestCase</code> 서브클래스, 메서드의 전체 경로를 지정해주면 됩니다.</p> + +<pre class="brush: bash notranslate"># Run the specified module +python3 manage.py test catalog.tests + +# Run the specified module +python3 manage.py test catalog.tests.test_models + +# Run the specified class +python3 manage.py test catalog.tests.test_models.YourTestClass + +# Run the specified method +python3 manage.py test catalog.tests.test_models.YourTestClass.test_one_plus_one_equals_two +</pre> + +<h2 id="LocalLibrary_테스트">LocalLibrary 테스트</h2> + +<p>테스트를 어떻게 돌릴지와 어떤 내용을 테스트할지를 알았으니 이제 실제 예제들을 봅시다.</p> + +<div class="note"> +<p><strong>Note: </strong>우리는 가능한 모든 테스트를 작성하지는 않을 것입니다. 하지만 아래의 예제만으로도 테스트가 어떻게 동작하는지와 어떤 테스트를 작성할 수 있을지 아이디어를 얻을 수 있을 것입니다.</p> +</div> + +<h3 id="모델">모델</h3> + +<p>위에서 논의했듯이 우리는 우리가 디자인 했거나, 우리가 작성한 코드의 동작만을 테스트해야하지 Django 또는 Python 개발팀에서 이미 테스트 한 라이브러리 / 코드는 테스트하지 않아야 합니다.</p> + +<p>예를 들어, 아래 <code>Author</code> 모델을 봅시다. 여기서 우리는 모든 필드의 라벨을 테스트해야 합니다. 우리가 필드의 라벨을 지정하지는 않았지만 우리의 디자인은 라벨의 값이 어때야하는지를 이미 정해놓고 있기 때문입니다. 우리가 이 값들을 테스트하지 않는다면 필드 라벨에 의도된 값을 가지는지 알 수 없습니다. 마찬가지로 비록 우리는 Django가 필드들을 지정된 길이대로 만들 것이라고 믿지만, 그래도 필드의 길이를 테스트해보는 것이 헛되지는 않습니다.</p> + +<pre class="brush: python notranslate">class Author(models.Model): + first_name = models.CharField(max_length=100) + last_name = models.CharField(max_length=100) + date_of_birth = models.DateField(null=True, blank=True) + date_of_death = models.DateField('Died', null=True, blank=True) + + def get_absolute_url(self): + return reverse('author-detail', args=[str(self.id)]) + + def __str__(self): + return f'{self.last_name}, {self.first_name}'</pre> + +<p><strong>/catalog/tests/test_models.py </strong>을 열어서 기존 코드를 다음의 <code>Author</code> 모델 테스트 코드로 바꿔주세요.</p> + +<p>먼저 우리는 <code>TestCase</code> 를 불러온 후 이를 상속해서 우리의 테스트 케이스인 <code>AuthorModelTest</code> 를 작성합니다. 테스트가 실패할 경우 출력에서 테스트 명을 쉽게 파악할 수 있도록 이름을 작성한 것에 주목해 주세요. 또 우리는 <code>setUpTestData()</code>를 불러서 테스트 시에 이용되지만 수정은 가하지 않는 저자 객체를 생성합니다. </p> + +<pre class="brush: python notranslate">from django.test import TestCase + +from catalog.models import Author + +class AuthorModelTest(TestCase): + @classmethod + def setUpTestData(cls): + # Set up non-modified objects used by all test methods + Author.objects.create(first_name='Big', last_name='Bob') + + def test_first_name_label(self): + author = Author.objects.get(id=1) + field_label = author._meta.get_field('first_name').verbose_name + self.assertEquals(field_label, 'first name') + + def test_date_of_death_label(self): + author=Author.objects.get(id=1) + field_label = author._meta.get_field('date_of_death').verbose_name + self.assertEquals(field_label, 'died') + + def test_first_name_max_length(self): + author = Author.objects.get(id=1) + max_length = author._meta.get_field('first_name').max_length + self.assertEquals(max_length, 100) + + def test_object_name_is_last_name_comma_first_name(self): + author = Author.objects.get(id=1) + expected_object_name = f'{author.last_name}, {author.first_name}' + self.assertEquals(expected_object_name, str(author)) + + def test_get_absolute_url(self): + author = Author.objects.get(id=1) + # This will also fail if the urlconf is not defined. + self.assertEquals(author.get_absolute_url(), '/catalog/author/1')</pre> + +<p>필드 테스트들은 필드 라벨의 값(<code>verbose_name</code>)을 확인하고 character 필드의 크기가 예상대로인지를 확인합니다. 이들 테스트 메소드의 변수명은 모두 메소드의 기능을 묘사하고 있으며 같은 규칙을 따릅니다.</p> + +<pre class="brush: python notranslate"># Get an author object to test +author = Author.objects.get(id=1) + +# Get the metadata for the required field and use it to query the required field data +field_label = author._meta.get_field('first_name').verbose_name + +# Compare the value to the expected result +self.assertEquals(field_label, 'first name')</pre> + +<p>몇 가지 흥미로운 점들이 있습니다:</p> + +<ul> + <li>우리는 <code>author.first_name.verbose_name</code> 을 이용해서 <code>verbose_name</code>을 얻지 않습니다. 왜냐면 <code>author.first_name</code>은 문자열이지 우리가 속성에 접근할 수 있는 <code>first_name</code>객체가 아니기 때문입니다. 대신 우리는 author 객체의 <code>_meta</code> 속성을 이용해서 필드에 접근하여 필요한 정보를 얻습니다. </li> + <li>우리는 <code>assertTrue(field_label == 'first name'</code> 대신 <code>assertEquals(field_label,'first name')</code> 을 이용했습니다. 왜냐면 만약 테스트가 실패할 경우 후자는 실제 라벨의 값을 알려주어 디버깅을 조금 더 용이하게 만들어주기 때문입니다.</li> +</ul> + +<div class="note"> +<p><strong>Note:</strong> <code>last_name</code> 과 <code>date_of_birth</code> 필드의 라벨에 대한 테스트와 <code>last_name</code> 필드의 길이에 대한 테스트는 생략되었습니다. 기존 테스트의 이름 작성 규칙 (naming convention)과 테스트 작성법을 이용해서 직접 테스트를 작성해보세요. </p> +</div> + +<p>우리는 우리가 작성한 메서드도 테스트를 해야 합니다. 객체의 이름이 우리가 예상한 대로 "Last Name", "First Name" 규칙에 맞게 생성되었는지와 <code>Author</code> 객체의 URL이 우리가 예상한 대로 생성되는지를 보면 됩니다. </p> + +<pre class="brush: python notranslate">def test_object_name_is_last_name_comma_first_name(self): + author = Author.objects.get(id=1) + expected_object_name = f'{author.last_name}, {author.first_name}' + self.assertEquals(expected_object_name, str(author)) + +def test_get_absolute_url(self): + author = Author.objects.get(id=1) + # This will also fail if the urlconf is not defined. + self.assertEquals(author.get_absolute_url(), '/catalog/author/1')</pre> + +<p>테스트들을 돌려봅시다. Author 모델을 앞선 튜토리얼에 따라 만들었다면 아마 다음과 같이 <code>date_of_death</code> 라벨에 대한 에러가 나올 것입니다. 이 테스트는 라벨명이 라벨의 첫글자를 대문자로 처리하지 않는 장고의 컨벤션에 따라 생성된 것을 가정했기 때문에 실패합니다.</p> + +<pre class="brush: bash notranslate">====================================================================== +FAIL: test_date_of_death_label (catalog.tests.test_models.AuthorModelTest) +---------------------------------------------------------------------- +Traceback (most recent call last): + File "D:\...\locallibrary\catalog\tests\test_models.py", line 32, in test_date_of_death_label + self.assertEquals(field_label,'died') +AssertionError: 'Died' != 'died' +- Died +? ^ ++ died +? ^</pre> + +<p>이는 아주 사소한 버그이지만, 테스트를 작성하는 것이 코드를 작성할 때 하는 가정들을 얼마나 꼼꼼히 체크하는지를 보여줍니다. </p> + +<div class="note"> +<p><strong>Note: </strong> date_of_death 필드의 라벨을 (/catalog/models.py) "died" 로 바꾸고 테스트를 다시 돌려보세요.</p> +</div> + +<p>다른 모델을 테스트하는 패턴도 이와 비슷하므로 여기서는 더 다루지 않겠습니다. 다른 모델에 대한 테스트 코드도 직접 작성해 보세요.</p> + +<h3 id="Forms">Forms</h3> + +<p>Forms를 테스트 하는 것은 모델을 테스트 하는 것과 비슷합니다; 당신이 만들고 디자인한 세세한 모든 것들은 테스트가 필요하며, 프레임워크나 써드 파티 라이브러리 등에 대해서는 테스트를 작성하지 않아도 좋습니다.</p> + +<p>따라서 폼에 대한 테스트 코드를 작성할 때는 보통 폼이 우리가 원하는 필드를 가지고 있는지, 그리고 이들 필드들이 적절한 라벨과 도움말과 함께 나타나는지를 테스트하면 됩니다. 직접 별도의 필드와 검증 로직을 작성하지 않은 이상 장고가 필드 타입을 제대로 검증하는지는 테스트 하지 않아도 됩니다 - 예를 들어 이메일 필드가 정말로 이메일 주소 값만을 받아들이는지 직접 테스트 할 필요가 없습니다. 하지만 필드에 대한 다른 추가적인 유효성 검증 로직과 다른 에러 메시지에 대해서는 테스트가 필요합니다.</p> + +<p>책 정보를 갱신하기 위한 우리의 Form을 생각해봅시다. 이 Form은 갱신 날짜를 위한 하나의 필드를 가지고 있으며 해당 필드는 우리가 테스트해야 할 라벨과 도움말을 가지고 있습니다.</p> + +<pre class="brush: python notranslate">class RenewBookForm(forms.Form): + """Form for a librarian to renew books.""" + renewal_date = forms.DateField(help_text="Enter a date between now and 4 weeks (default 3).") + + def clean_renewal_date(self): + data = self.cleaned_data['renewal_date'] + + # Check if a date is not in the past. + if data < datetime.date.today(): + raise ValidationError(_('Invalid date - renewal in past')) + + # Check if date is in the allowed range (+4 weeks from today). + if data > datetime.date.today() + datetime.timedelta(weeks=4): + raise ValidationError(_('Invalid date - renewal more than 4 weeks ahead')) + + # Remember to always return the cleaned data. + return data</pre> + +<p><strong>/catalog/tests/test_forms.py</strong> 을 열어서 기존 코드를 아래의 <code>RenewBookForm</code> 테스트 코드로 바꿔주세요. 아래 코드는 우선 우리의 Form과 시간에 관련한 로직 테스트를 도와줄 파이썬 및 장고 라이브러리를 불러옵니다. 그리고 우리는 모델을 테스트 했을 때와 마찬가지로 Form 테스트 클래스를 선언하고, 마찬가지로 테스트의 목적과 기능을 알려주는 이름을 지어줬습니다.</p> + +<pre class="brush: python notranslate">import datetime + +from django.test import TestCase +from django.utils import timezone + +from catalog.forms import RenewBookForm + +class RenewBookFormTest(TestCase): + def test_renew_form_date_field_label(self): + form = RenewBookForm() + self.assertTrue(form.fields['renewal_date'].label == None or form.fields['renewal_date'].label == 'renewal date') + + def test_renew_form_date_field_help_text(self): + form = RenewBookForm() + self.assertEqual(form.fields['renewal_date'].help_text, 'Enter a date between now and 4 weeks (default 3).') + + def test_renew_form_date_in_past(self): + date = datetime.date.today() - datetime.timedelta(days=1) + form = RenewBookForm(data={'renewal_date': date}) + self.assertFalse(form.is_valid()) + + def test_renew_form_date_too_far_in_future(self): + date = datetime.date.today() + datetime.timedelta(weeks=4) + datetime.timedelta(days=1) + form = RenewBookForm(data={'renewal_date': date}) + self.assertFalse(form.is_valid()) + + def test_renew_form_date_today(self): + date = datetime.date.today() + form = RenewBookForm(data={'renewal_date': date}) + self.assertTrue(form.is_valid()) + + def test_renew_form_date_max(self): + date = timezone.now() + datetime.timedelta(weeks=4) + form = RenewBookForm(data={'renewal_date': date}) + self.assertTrue(form.is_valid())</pre> + +<p>앞의 두 함수는 필드의 라벨과 도움말이 예상대로 생성되었는지를 확인합니다. 우리는 필드를 fields 딕셔너리를 통해서 접근했습니다 (e.g. <code>form.fields['renewal_date']</code>). 라벨의 값이 <code>None</code> 인지도 확인해야하는 것을 기억해 두세요. 장고가 올바른 라벨을 렌더하더라도 만약 라벨의 값이 명시적으로 정해지지 않았다면 <code>None</code> 이 반환됩니다.</p> + +<p>나머지 함수들은 폼이 적절한 구간 내에 있는 갱신 일자를 수락하는지와 더불어 부적합한 구간에 있는 일자를 거절하는지를 테스트 합니다. 우리가 테스트용 날짜들을 <code>datetime.timedelta()</code> (몇 일이나 몇 주를 나타냅니다)을 이용해서 현재 날짜 근처로(<code>datetime.date.today()</code> ) 생성하는 것을 기억해두세요. 그리고나서 우리는 폼을 만들고, 데이터를 집어넣고, 데이터가 유효한지를 테스트합니다.</p> + +<div class="note"> +<p><strong>Note:</strong> 여기서 우리는 데이터베이스나 테스트 클라이언트를 사용하지 않습니다. <a href="https://docs.djangoproject.com/en/2.0/topics/testing/tools/#django.test.SimpleTestCase">SimpleTestCase</a>를 이용해서 테스트 클래스를 만드는 것을 고려해보세요.</p> + +<p>또한 우리는 만약 폼이 유효하지 않을 경우 적절한 에러가 발생하는지 역시 검증해야 합니다. 하지만 보통 이 부분은 view processing의 일부로 처리되기 때문에 다음 섹션에서 다루도록 하겠습니다.</p> +</div> + +<p>이것이 form에 대한 전부입니다. 비록 다른 폼들이 있지만, 이들은 우리의 클래스 기반 편집 뷰에 의해 생성된 것들이기 때문에 그쪽에서 테스트 되어야 합니다. 테스트를 실행하고 우리의 코드가 여전히 테스트를 통과하는지 확인해 보세요.</p> + +<h3 id="Views">Views</h3> + +<p>우리의 뷰 동작을 유효하게 하기 위해서 우리는 Django test <a href="https://docs.djangoproject.com/en/2.0/topics/testing/tools/#django.test.Client">Client</a>를 사용합니다. 이 클래스는 더미 웹 브라우저와 같이 동작하는데, 우리는 URL의 <code>GET</code> 과 <code>POST</code> 요청을 동시에 하여 그 반응을 살핍니다. 우리는 저수준의 HTTP (응답의 헤더와 상태 코드) 부터 HTML을 렌더하기 위한 템플릿, 그리고 우리가 템플릿에 입력하는 컨텍스트 데이터까지 응답에 대한 거의 모든 것을 확인할 수 있습니다. 또한 우리는 (만약 이뤄진다면) redirect가 진행되는 단계와 각 단계에 대한 URL 및 상태 코드 역시 확인할 수 있습니다. 이를 통해서 우리는 각 뷰가 예상된 대로 동작하는지를 확인할 수 있습니다.</p> + +<p>우리의 가장 간단한 뷰 중 하나인 모든 저자들의 목록을 반환하는 뷰부터 시작해봅시다. 이 뷰는 <strong>/catalog/authors/</strong> URL(URL 설정 상에서 'authors'로 명명되었습니다) 에서 출력됩니다.</p> + +<pre class="brush: python notranslate">class AuthorListView(generic.ListView): + model = Author + paginate_by = 10</pre> + +<p>이 뷰가 generic list 뷰이다 보니 거의 모든 것이 장고에 의해서 처리됩니다. 만약 장고를 믿는다면 우리는 오로지 뷰가 올바른 URL과 뷰 이름으로 접근 가능한지만 테스트하면 됩니다. 하지만 만약 테스트 주도 방법론 (TDD)를 따른다면 우리는 (코드를 작성하기 전에) 뷰가 모든 저자들을 10명 씩 paginate해서 보여주는지를 확인하는 테스트부터 작성해야 합니다.</p> + +<p><strong>/catalog/tests/test_views.py</strong>를 열어서 기존 코드를 다음의 <code>AuthorListView</code> 테스트 코드로 바꿔주세요. 앞서와 마찬가지로 우리 모델과 유용한 클래스들을 불러옵니다.<code>setUpTestData()</code> 에서는 pagination을 테스트하기 위해 <code>Author</code> 객체 여러 개를 생성합니다.</p> + +<pre class="brush: python notranslate">from django.test import TestCase +from django.urls import reverse + +from catalog.models import Author + +class AuthorListViewTest(TestCase): + @classmethod + def setUpTestData(cls): + # Create 13 authors for pagination tests + number_of_authors = 13 + + for author_id in range(number_of_authors): + Author.objects.create( + first_name=f'Christian {author_id}', + last_name=f'Surname {author_id}', + ) + + def test_view_url_exists_at_desired_location(self): + response = self.client.get('/catalog/authors/') + self.assertEqual(response.status_code, 200) + + def test_view_url_accessible_by_name(self): + response = self.client.get(reverse('authors')) + self.assertEqual(response.status_code, 200) + + def test_view_uses_correct_template(self): + response = self.client.get(reverse('authors')) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, 'catalog/author_list.html') + + def test_pagination_is_ten(self): + response = self.client.get(reverse('authors')) + self.assertEqual(response.status_code, 200) + self.assertTrue('is_paginated' in response.context) + self.assertTrue(response.context['is_paginated'] == True) + self.assertTrue(len(response.context['author_list']) == 10) + + def test_lists_all_authors(self): + # Get second page and confirm it has (exactly) remaining 3 items + response = self.client.get(reverse('authors')+'?page=2') + self.assertEqual(response.status_code, 200) + self.assertTrue('is_paginated' in response.context) + self.assertTrue(response.context['is_paginated'] == True) + self.assertTrue(len(response.context['author_list']) == 3)</pre> + +<p>모든 테스트는 <code>TestCase</code>를 상속한 우리 테스트 클래스에 있는 클라이언트를 이용해서 <code>GET</code> 요청을 하고 그에 따른 응답을 받습니다. 첫번째 테스트는 특정 URL (도메인이 아닌 상대 경로임을 기억하세요) 을 확인하고 두번째 테스트는 URL 설정에서 설정해준 뷰의 이름에서 얻은 URL을 확인합니다.</p> + +<pre class="brush: python notranslate">response = self.client.get('/catalog/authors/') +response = self.client.get(reverse('authors'))</pre> + +<p>응답을 받으면 우리는 응답에서 상태 코드, 사용된 템플릿, pagination이 되었는지 여부, 반환된 객체의 갯수, 그리고 전체 아이템의 갯수를 확인합니다.</p> + +<p>우리가 검증하는 변수 중 가장 흥미로운 변수는 바로 <code>response.context</code>로 뷰에 의해서 템플릿에 전달되는 context 변수입니다. 이는 템플릿이 필요한 모든 데이터를 받는지를 검증할 수 있게 해주기 때문에 테스팅에 정말 유용합니다. 즉 우리는 어떤 템플릿이 사용되고 또 어떤 데이터가 템플릿에 전달되는지를 확인할 수 있기 때문에 자신있게 렌더링에 관한 나머지 문제들은 오로지 템플릿의 문제라고 생각할 수 있습니다.</p> + +<h4 id="로그인한_사용자에게만_보이는_뷰">로그인한 사용자에게만 보이는 뷰</h4> + +<p>종종 우리는 로그인 한 사용자에게만 보이는 뷰를 테스트하고 싶습니다. 예를 들어서 <code>LoanedBooksByUserListView</code>는 방금 테스트한 뷰와 비슷하지만 로그인한 유저만 접근할 수 있으며, 현재 유저가 대출한, '대출 중' 상태의 <code>BookInstance</code> 만 보여주며 가장 오래된 것 부터 먼저 보여줍니다.</p> + +<pre class="brush: python notranslate">from django.contrib.auth.mixins import LoginRequiredMixin + +class LoanedBooksByUserListView(LoginRequiredMixin, generic.ListView): + """Generic class-based view listing books on loan to current user.""" + model = BookInstance + template_name ='catalog/bookinstance_list_borrowed_user.html' + paginate_by = 10 + + def get_queryset(self): + return BookInstance.objects.filter(borrower=self.request.user).filter(status__exact='o').order_by('due_back')</pre> + +<p>아래 코드를 <strong>/catalog/tests/test_views.py </strong> 에 추가해주세요. 여기서 우리는 <code>SetUp()</code> 을 이용해서 계정을 생성한 다음 테스트에 사용할 <code>BookInstance</code> 객체와 관련된 책 및 기타 정보를 생성합니다. 각각의 테스트 계정에 의해서 책이 반반씩 대출되었지만 일단 우리는 모든 책의 상태를 "maintenance"로 설정합니다. 우리는 테스트 하면서 이들 객체들을 수정할 것이기 때문에 <code>setUpTestData()</code> 대신 <code>SetUp()</code>을 사용했습니다.</p> + +<div class="note"> +<p><strong>Note:</strong> 아래의 <code>setUp()</code> 코드는 특정 <code>Language</code>의 책을 생성하지만, <code>Language</code> 모델이 이전 튜토리얼에서 도전 과제로 생성되었기 때문에 여러분의 코드에는 존재하지 않을 수 있습니다. 이때는 간단히 <code>Language</code> 객체를 불러오거나 생성하는 코드를 주석처리 해주세요. 같은 작업을 곧 나올 <code>RenewBookInstancesViewTest</code> 에도 해줘야 합니다.</p> +</div> + +<pre class="brush: python notranslate">import datetime + +from django.utils import timezone +from django.contrib.auth.models import User # Required to assign User as a borrower + +from catalog.models import BookInstance, Book, Genre, Language + +class LoanedBookInstancesByUserListViewTest(TestCase): + def setUp(self): + # Create two users + test_user1 = User.objects.create_user(username='testuser1', password='1X<ISRUkw+tuK') + test_user2 = User.objects.create_user(username='testuser2', password='2HJ1vRV0Z&3iD') + + test_user1.save() + test_user2.save() + + # Create a book + test_author = Author.objects.create(first_name='John', last_name='Smith') + test_genre = Genre.objects.create(name='Fantasy') + test_language = Language.objects.create(name='English') + test_book = Book.objects.create( + title='Book Title', + summary='My book summary', + isbn='ABCDEFG', + author=test_author, + language=test_language, + ) + + # Create genre as a post-step + genre_objects_for_book = Genre.objects.all() + test_book.genre.set(genre_objects_for_book) # Direct assignment of many-to-many types not allowed. + test_book.save() + + # Create 30 BookInstance objects + number_of_book_copies = 30 + for book_copy in range(number_of_book_copies): + return_date = timezone.now() + datetime.timedelta(days=book_copy%5) + the_borrower = test_user1 if book_copy % 2 else test_user2 + status = 'm' + BookInstance.objects.create( + book=test_book, + imprint='Unlikely Imprint, 2016', + due_back=return_date, + borrower=the_borrower, + status=status, + ) + + def test_redirect_if_not_logged_in(self): + response = self.client.get(reverse('my-borrowed')) + self.assertRedirects(response, '/accounts/login/?next=/catalog/mybooks/') + + def test_logged_in_uses_correct_template(self): + login = self.client.login(username='testuser1', password='1X<ISRUkw+tuK') + response = self.client.get(reverse('my-borrowed')) + + # Check our user is logged in + self.assertEqual(str(response.context['user']), 'testuser1') + # Check that we got a response "success" + self.assertEqual(response.status_code, 200) + + # Check we used correct template + self.assertTemplateUsed(response, 'catalog/bookinstance_list_borrowed_user.html')</pre> + +<p>뷰가 로그인하지 않은 사용자를 로그인 화면으로 redirect 하는 것을 확인하기 위해 우리는 <code>assertRedirects</code>를 사용함을 <code>test_redirect_if_not_logged_in()</code>에서 확인할 수 있습니다. 페이지가 로그인 한 사용자에게 보임을 확인하기 위해서 우리는 테스트 유저로 로그인을 한 후에 페이지에 접근해서 응답의 상태코드가 200번임을 확인합니다 (성공을 의미).</p> + +<p>나머지 테스트 코드는 뷰가 현재 로그인 한 사용자가 대출한 책만을 반환하는지를 검증합니다. 아래의 코드를 위의 테스트 클래스 아래에 붙여 넣어 주세요.</p> + +<pre class="brush: python notranslate"> def test_only_borrowed_books_in_list(self): + login = self.client.login(username='testuser1', password='1X<ISRUkw+tuK') + response = self.client.get(reverse('my-borrowed')) + + # Check our user is logged in + self.assertEqual(str(response.context['user']), 'testuser1') + # Check that we got a response "success" + self.assertEqual(response.status_code, 200) + + # Check that initially we don't have any books in list (none on loan) + self.assertTrue('bookinstance_list' in response.context) + self.assertEqual(len(response.context['bookinstance_list']), 0) + + # Now change all books to be on loan + books = BookInstance.objects.all()[:10] + + for book in books: + book.status = 'o' + book.save() + + # Check that now we have borrowed books in the list + response = self.client.get(reverse('my-borrowed')) + # Check our user is logged in + self.assertEqual(str(response.context['user']), 'testuser1') + # Check that we got a response "success" + self.assertEqual(response.status_code, 200) + + self.assertTrue('bookinstance_list' in response.context) + + # Confirm all books belong to testuser1 and are on loan + for bookitem in response.context['bookinstance_list']: + self.assertEqual(response.context['user'], bookitem.borrower) + self.assertEqual('o', bookitem.status) + + def test_pages_ordered_by_due_date(self): + # Change all books to be on loan + for book in BookInstance.objects.all(): + book.status='o' + book.save() + + login = self.client.login(username='testuser1', password='1X<ISRUkw+tuK') + response = self.client.get(reverse('my-borrowed')) + + # Check our user is logged in + self.assertEqual(str(response.context['user']), 'testuser1') + # Check that we got a response "success" + self.assertEqual(response.status_code, 200) + + # Confirm that of the items, only 10 are displayed due to pagination. + self.assertEqual(len(response.context['bookinstance_list']), 10) + + last_date = 0 + for book in response.context['bookinstance_list']: + if last_date == 0: + last_date = book.due_back + else: + self.assertTrue(last_date <= book.due_back) + last_date = book.due_back</pre> + +<p>당신은 pagination 역시 테스트 할 수 있습니다. 한 번 해보셨으면 좋겠습니다 :)</p> + +<h4 id="Form을_이용하는_view를_테스트하기">Form을 이용하는 view를 테스트하기</h4> + +<p>Form을 이용하는 뷰를 테스트하는 것은 앞선 경우에 비해 살짝 더 복잡합니다. 왜냐면 우리는 코드의 더 다양한 부분을 - 첫 화면, 데이터 유효성 검증이 실패한 화면, 데이터 유효성 검증이 성공한 화면 - 모두를 테스트해야 하기 때문입니다. 다행히 우리는 데이터를 보여주기만 하는 뷰를 테스트 할 때 사용했던 클라이언트를 거의 그대로 사용할 수 있습니다.</p> + +<p>대출을 갱신하기 위한 뷰를 테스트하기 위한 코드를 짜봅시다 (<code>renew_book_librarian()</code>):</p> + +<pre class="brush: python notranslate">from catalog.forms import RenewBookForm + +@permission_required('catalog.can_mark_returned') +def renew_book_librarian(request, pk): + """View function for renewing a specific BookInstance by librarian.""" + book_instance = get_object_or_404(BookInstance, pk=pk) + + # If this is a POST request then process the Form data + if request.method == 'POST': + + # Create a form instance and populate it with data from the request (binding): + book_renewal_form = RenewBookForm(request.POST) + + # Check if the form is valid: + if form.is_valid(): + # process the data in form.cleaned_data as required (here we just write it to the model due_back field) + book_instance.due_back = form.cleaned_data['renewal_date'] + book_instance.save() + + # redirect to a new URL: + return HttpResponseRedirect(reverse('all-borrowed')) + + # If this is a GET (or any other method) create the default form + else: + proposed_renewal_date = datetime.date.today() + datetime.timedelta(weeks=3) + book_renewal_form = RenewBookForm(initial={'renewal_date': proposed_renewal_date}) + + context = { + 'book_renewal_form': book_renewal_form, + 'book_instance': book_instance, + } + + return render(request, 'catalog/book_renew_librarian.html', context)</pre> + +<p>이제 우리는 <code>can_mark_returned</code> permission을 가진 사용자만이 view를 사용할 수 있는지, 그리고 그 사용자들이 가지고 있지 않은 <code>BookInstance</code> 을 수정하려고 시도하면 HTTP 404 에러 페이지로 리다이렉트 되는지 테스트해봐야 합니다. We should check that the initial value of the form is seeded with a date three weeks in the future, and that if validation succeeds we're redirected to the "all-borrowed books" view. As part of checking the validation-fail tests we'll also check that our form is sending the appropriate error messages.</p> + +<p>Add the first part of the test class (shown below) to the bottom of <strong>/catalog/tests/test_views.py</strong>. This creates two users and two book instances, but only gives one user the permission required to access the view. The code to grant permissions during tests is shown in bold:</p> + +<pre class="brush: python notranslate">import uuid + +from django.contrib.auth.models import Permission # Required to grant the permission needed to set a book as returned. + +class RenewBookInstancesViewTest(TestCase): + def setUp(self): + # Create a user + test_user1 = User.objects.create_user(username='testuser1', password='1X<ISRUkw+tuK') + test_user2 = User.objects.create_user(username='testuser2', password='2HJ1vRV0Z&3iD') + + test_user1.save() + test_user2.save() + +<strong> permission = Permission.objects.get(name='Set book as returned') + test_user2.user_permissions.add(permission) + test_user2.save()</strong> + + # Create a book + test_author = Author.objects.create(first_name='John', last_name='Smith') + test_genre = Genre.objects.create(name='Fantasy') + test_language = Language.objects.create(name='English') + test_book = Book.objects.create( + title='Book Title', + summary='My book summary', + isbn='ABCDEFG', + author=test_author, + language=test_language, + ) + + # Create genre as a post-step + genre_objects_for_book = Genre.objects.all() + test_book.genre.set(genre_objects_for_book) # Direct assignment of many-to-many types not allowed. + test_book.save() + + # Create a BookInstance object for test_user1 + return_date = datetime.date.today() + datetime.timedelta(days=5) + self.test_bookinstance1 = BookInstance.objects.create( + book=test_book, + imprint='Unlikely Imprint, 2016', + due_back=return_date, + borrower=test_user1, + status='o', + ) + + # Create a BookInstance object for test_user2 + return_date = datetime.date.today() + datetime.timedelta(days=5) + self.test_bookinstance2 = BookInstance.objects.create( + book=test_book, + imprint='Unlikely Imprint, 2016', + due_back=return_date, + borrower=test_user2, + status='o', + )</pre> + +<p>Add the following tests to the bottom of the test class. These check that only users with the correct permissions (<em>testuser2</em>) can access the view. We check all the cases: when the user is not logged in, when a user is logged in but does not have the correct permissions, when the user has permissions but is not the borrower (should succeed), and what happens when they try to access a <code>BookInstance</code> that doesn't exist. We also check that the correct template is used.</p> + +<pre class="brush: python notranslate"> def test_redirect_if_not_logged_in(self): + response = self.client.get(reverse('renew-book-librarian', kwargs={'pk': self.test_bookinstance1.pk})) + # Manually check redirect (Can't use assertRedirect, because the redirect URL is unpredictable) + self.assertEqual(response.status_code, 302) + self.assertTrue(response.url.startswith('/accounts/login/')) + + def test_redirect_if_logged_in_but_not_correct_permission(self): + login = self.client.login(username='testuser1', password='1X<ISRUkw+tuK') + response = self.client.get(reverse('renew-book-librarian', kwargs={'pk': self.test_bookinstance1.pk})) + + # Manually check redirect (Can't use assertRedirect, because the redirect URL is unpredictable) + self.assertEqual(response.status_code, 302) + self.assertTrue(response.url.startswith('/accounts/login/')) + + def test_logged_in_with_permission_borrowed_book(self): + login = self.client.login(username='testuser2', password='2HJ1vRV0Z&3iD') + response = self.client.get(reverse('renew-book-librarian', kwargs={'pk': self.test_bookinstance2.pk})) + + # Check that it lets us login - this is our book and we have the right permissions. + self.assertEqual(response.status_code, 200) + + def test_logged_in_with_permission_another_users_borrowed_book(self): + login = self.client.login(username='testuser2', password='2HJ1vRV0Z&3iD') + response = self.client.get(reverse('renew-book-librarian', kwargs={'pk': self.test_bookinstance1.pk})) + + # Check that it lets us login. We're a librarian, so we can view any users book + self.assertEqual(response.status_code, 200) + + def test_HTTP404_for_invalid_book_if_logged_in(self): + # unlikely UID to match our bookinstance! + test_uid = uuid.uuid4() + login = self.client.login(username='testuser2', password='2HJ1vRV0Z&3iD') + response = self.client.get(reverse('renew-book-librarian', kwargs={'pk':test_uid})) + self.assertEqual(response.status_code, 404) + + def test_uses_correct_template(self): + login = self.client.login(username='testuser2', password='2HJ1vRV0Z&3iD') + response = self.client.get(reverse('renew-book-librarian', kwargs={'pk': self.test_bookinstance1.pk})) + self.assertEqual(response.status_code, 200) + + # Check we used correct template + self.assertTemplateUsed(response, 'catalog/book_renew_librarian.html') +</pre> + +<p>아래에 보이는 것처럼 새로운 테스트 방법을 추가해봅시다. 이것은 form의 초기 날짜가 3주 후인지를 확인합니다. 어떻게 우리가 form 필드의 첫 번째 값에 접근하는 것이 가능한지 참고해보세요. (굵게 표시된 부분에서 확인할 수 있습니다.)</p> + +<pre class="brush: python notranslate"> def test_form_renewal_date_initially_has_date_three_weeks_in_future(self): + login = self.client.login(username='testuser2', password='2HJ1vRV0Z&3iD') + response = self.client.get(reverse('renew-book-librarian', kwargs={'pk': self.test_bookinstance1.pk})) + self.assertEqual(response.status_code, 200) + + date_3_weeks_in_future = datetime.date.today() + datetime.timedelta(weeks=3) + self.assertEqual(response<strong>.context['form'].initial['renewal_date']</strong>, date_3_weeks_in_future)</pre> + +<div class="warning"> +<p>만약 당신이 class <code>RenewBookForm(forms.Form)</code> 대신에 class <code>RenewBookModelForm(forms.ModelForm)</code> 을 사용한다면, form의 필드명은 <strong>'renewal_date' </strong>대신 <strong>'due_back'</strong>으로 나타날 것입니다.</p> +</div> + +<p>The next test (add this to the class too) checks that the view redirects to a list of all borrowed books if renewal succeeds. What differs here is that for the first time we show how you can <code>POST</code> data using the client. The post <em>data</em> is the second argument to the post function, and is specified as a dictionary of key/values.</p> + +<pre class="brush: python notranslate"> def test_redirects_to_all_borrowed_book_list_on_success(self): + login = self.client.login(username='testuser2', password='2HJ1vRV0Z&3iD') + valid_date_in_future = datetime.date.today() + datetime.timedelta(weeks=2) + <strong>response = self.client.post(reverse('renew-book-librarian', kwargs={'pk':self.test_bookinstance1.pk,}), {'renewal_date':valid_date_in_future})</strong> + self.assertRedirects(response, reverse('all-borrowed')) +</pre> + +<div class="warning"> +<p>The <em>all-borrowed</em> view was added as a <em>challenge</em>, and your code may instead redirect to the home page '/'. If so, modify the last two lines of the test code to be like the code below. The <code>follow=True</code> in the request ensures that the request returns the final destination URL (hence checking <code>/catalog/</code> rather than <code>/</code>).</p> + +<pre class="brush: python notranslate"> response = self.client.post(reverse('renew-book-librarian', kwargs={'pk':self.test_bookinstance1.pk,}), {'renewal_date':valid_date_in_future}, <strong>follow=True</strong> ) + <strong>self.assertRedirects(</strong><strong>response, '/catalog/')</strong></pre> +</div> + +<p>Copy the last two functions into the class, as seen below. These again test <code>POST</code> requests, but in this case with invalid renewal dates. We use <code>assertFormError() </code>to verify that the error messages are as expected.</p> + +<pre class="brush: python notranslate"> def test_form_invalid_renewal_date_past(self): + login = self.client.login(username='testuser2', password='2HJ1vRV0Z&3iD') + date_in_past = datetime.date.today() - datetime.timedelta(weeks=1) + response = self.client.post(reverse('renew-book-librarian', kwargs={'pk': self.test_bookinstance1.pk}), {'renewal_date': date_in_past}) + self.assertEqual(response.status_code, 200) + <strong>self.assertFormError(</strong><strong>response, 'form', 'renewal_date', 'Invalid date - renewal in past')</strong> + + def test_form_invalid_renewal_date_future(self): + login = self.client.login(username='testuser2', password='2HJ1vRV0Z&3iD') + invalid_date_in_future = datetime.date.today() + datetime.timedelta(weeks=5) + response = self.client.post(reverse('renew-book-librarian', kwargs={'pk': self.test_bookinstance1.pk}), {'renewal_date': invalid_date_in_future}) + self.assertEqual(response.status_code, 200) + <strong>self.assertFormError(</strong><strong>response, 'form', 'renewal_date', 'Invalid date - renewal more than 4 weeks ahead')</strong> +</pre> + +<p>The same sorts of techniques can be used to test the other view.</p> + +<h3 id="Templates">Templates</h3> + +<p>Django provides test APIs to check that the correct template is being called by your views, and to allow you to verify that the correct information is being sent. There is however no specific API support for testing in Django that your HTML output is rendered as expected.</p> + +<h2 id="Other_recommended_test_tools">Other recommended test tools</h2> + +<p>Django's test framework can help you write effective unit and integration tests — we've only scratched the surface of what the underlying <strong>unittest</strong> framework can do, let alone Django's additions (for example, check out how you can use <a href="https://docs.python.org/3.5/library/unittest.mock-examples.html">unittest.mock</a> to patch third party libraries so you can more thoroughly test your own code).</p> + +<p>While there are numerous other test tools that you can use, we'll just highlight two:</p> + +<ul> + <li><a href="http://coverage.readthedocs.io/en/latest/">Coverage</a>: This Python tool reports on how much of your code is actually executed by your tests. It is particularly useful when you're getting started, and you are trying to work out exactly what you should test.</li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Your_own_automation_environment">Selenium</a> is a framework to automate testing in a real browser. It allows you to simulate a real user interacting with the site, and provides a great framework for system testing your site (the next step up from integration testing).</li> +</ul> + +<h2 id="Challenge_yourself">Challenge yourself</h2> + +<p>There are a lot more models and views we can test. As a simple task, try to create a test case for the <code>AuthorCreate</code> view.</p> + +<pre class="brush: python notranslate">class AuthorCreate(PermissionRequiredMixin, CreateView): + model = Author + fields = '__all__' + initial = {'date_of_death':'12/10/2016'} + permission_required = 'catalog.can_mark_returned'</pre> + +<p>Remember that you need to check anything that you specify or that is part of the design. This will include who has access, the initial date, the template used, and where the view redirects on success.</p> + +<h2 id="Summary">Summary</h2> + +<p>Writing test code is neither fun nor glamorous, and is consequently often left to last (or not at all) when creating a website. It is however an essential part of making sure that your code is safe to release after making changes, and cost-effective to maintain.</p> + +<p>In this tutorial we've shown you how to write and run tests for your models, forms, and views. Most importantly we've provided a brief summary of what you should test, which is often the hardest thing to work out when you're getting started. There is a lot more to know, but even with what you've learned already you should be able to create effective unit tests for your websites.</p> + +<p>The next and final tutorial shows how you can deploy your wonderful (and fully tested!) Django website.</p> + +<h2 id="See_also">See also</h2> + +<ul> + <li><a href="https://docs.djangoproject.com/en/2.0/topics/testing/overview/">Writing and running tests</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.0/intro/tutorial05/">Writing your first Django app, part 5 > Introducing automated testing</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.0/topics/testing/tools/">Testing tools reference</a> (Django docs)</li> + <li><a href="https://docs.djangoproject.com/en/2.0/topics/testing/advanced/">Advanced testing topics</a> (Django docs)</li> + <li><a href="http://toastdriven.com/blog/2011/apr/10/guide-to-testing-in-django/">A Guide to Testing in Django</a> (Toast Driven Blog, 2011)</li> + <li><a href="http://test-driven-django-development.readthedocs.io/en/latest/index.html">Workshop: Test-Driven Web Development with Django</a> (San Diego Python, 2014)</li> + <li><a href="https://realpython.com/blog/python/testing-in-django-part-1-best-practices-and-examples/">Testing in Django (Part 1) - Best Practices and Examples</a> (RealPython, 2013)</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Django/Forms", "Learn/Server-side/Django/Deployment", "Learn/Server-side/Django")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Server-side/Django/Introduction">Django introduction</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/development_environment">Setting up a Django development environment</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Django Tutorial: The Local Library website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django Tutorial Part 2: Creating a skeleton website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Models">Django Tutorial Part 3: Using models</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Admin_site">Django Tutorial Part 4: Django admin site</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django Tutorial Part 5: Creating our home page</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Generic_views">Django Tutorial Part 6: Generic list and detail views</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Sessions">Django Tutorial Part 7: Sessions framework</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Authentication">Django Tutorial Part 8: User authentication and permissions</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Forms">Django Tutorial Part 9: Working with forms</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Testing">Django Tutorial Part 10: Testing a Django web application</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Django Tutorial Part 11: Deploying Django to production</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/web_application_security">Django web application security</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></li> +</ul> diff --git a/files/ko/learn/server-side/django/tutorial_local_library_website/index.html b/files/ko/learn/server-side/django/tutorial_local_library_website/index.html new file mode 100644 index 0000000000..6cad27324e --- /dev/null +++ b/files/ko/learn/server-side/django/tutorial_local_library_website/index.html @@ -0,0 +1,92 @@ +--- +title: 'Django 튜토리얼: 지역 도서관 웹사이트' +slug: Learn/Server-side/Django/Tutorial_local_library_website +translation_of: Learn/Server-side/Django/Tutorial_local_library_website +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Django/development_environment", "Learn/Server-side/Django/skeleton_website", "Learn/Server-side/Django")}}</div> + +<p class="summary">이번은 실전 튜토리얼 시리즈의 첫번째 파트로서 당신이 배울 내용을 설명하고, 이어지는 튜토리얼 시리즈에서 개발하고 개선시켜볼 "지역 도서관" 예제 웹사이트에 대한 개요를 제공한다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">사전학습:</th> + <td><a href="/ko/docs/Learn/Server-side/Django/Introduction">Django 소개</a> 파트를 읽으세요. 이어지는 파트를 위해서는 <a href="/ko/docs/Learn/Server-side/Django/development_environment">Django개발 환경 설치하기</a> 파트도 필요합니다.</td> + </tr> + <tr> + <th scope="row">학습목표:</th> + <td>이 튜토리얼에서 사용될 예제 어플리케이션을 소개하고, 여기서 논의될 토픽들의 범위에 대해 이해하기</td> + </tr> + </tbody> +</table> + +<h2 id="개요">개요</h2> + +<p>MDN "로컬 라이브러리" 장고 튜토리얼에서 오신 것을 환영합니다. 여기에서는 , "로컬 라이브러리" 카탈로그를 운영하는데 사용될 수 있는 웹사이트를 개발할 것이다. </p> + +<p>이 튜토리얼 시리즈는 아래 내용을 다룬다:</p> + +<ul> + <li>웹 애플리케이션의 골격을 만들기 위해 장고 도구 사용하기</li> + <li>개발 서버 시작하기와 끝내기</li> + <li>애플리케이션 데이터의 틀이 되는 모델 생성하기</li> + <li>데이터를 입력하기 위해서 장고 관리자(admin) 사이트 사용하기</li> + <li>여러가지 요청에 따른 특정 데이터를 가져오는 뷰(view)와 브라우저상에서 이 데이타를 볼수 있도록 HTML로 렌더링하는 템플릿을 생성하기</li> + <li>여러가지 URL 패턴과 특정한 뷰를 연결하는 맵퍼(mappers) 만들기</li> + <li>사이트 동작과 접속을 통제하기 위한 유저 인증(authorization) & 세션 추가하기</li> + <li>폼으로 작업하기</li> + <li>앱을 테스트할 코드 작성하기</li> + <li>장고의 보안도구를 효과적으로 사용하기</li> + <li>애플리케이션을 운영환경에 배포하기</li> +</ul> + +<p>여러분은 이 토픽들 중 일부는 이미 배웠고, 나머지는 가볍게 경험했다. 이 튜토리얼 시리즈를 완료하면, 여러분은 간단한 장고 앱을 혼자서 충분히 개발할 수 있다. </p> + +<h2 id="LocalLibrary_웹사이트">LocalLibrary 웹사이트</h2> + +<p><em>LocalLibrary는 이 튜토리얼 시리즈에서 우리가 만들고 개선시켜나갈 웹사이트의 이름이다.</em> 이름에서 예상되듯이, 이용자들이 대여 가능한 책을 찾아보고 사용자 계정을 관리할 수 있는, 작은 지역 도서관을 위한 온라인 도서목록을 제공하는 것이 목적이다.</p> + +<p>이 예제는, 우리가 필요에 따라 크게 혹은 작게 확장할 수 있고, 대부분은 장고의 특성을 보여줄 수 있도록 아주 신중하게 선택된 예제이다. 더욱 중요한 것은 이 예제는 장고 웹 프레임워크의 가장 중요한 기능들을 경험해 보도록 안내된 경로를 제공한다:</p> + +<ul> + <li>처음 몇몇의 튜토리얼에서, 사용자가 어떤 책을 이용할 수 있는지 찾아볼 수 있도록, 간단한 둘러보기 전용 도서관 기능을 정의할 것이다. 이 내용은 거의 모든 웹사이트에서 일반적으로 제공되는 동작(데이타베이스에서 내용을 읽고 보여주는 것)을 탐색해볼 수 있도록 해줄 것이다.</li> + <li>튜토리얼을 좀 더 진행해 가면서, 도서관 예제는 좀 더 고급의 장고 기능을 보여줄 수 있도록 자연스럽게 확장된다. 예를 들면, 사용자가 책을 예약하도록 기능을 확장할 수 있고 이것을 이용해 폼을 사용하는 방법과 사용자 인증을 지원하는 방법을 보여줄 수 있다.</li> +</ul> + +<p>이것은 매우 확장성있는 예제이지만, 다음과 같은 이유로 <em><strong>Local</strong>Library(Local에 강조)로 이름을 지었다. 그 이유는, 당신이 장고 개발을 빠르게 착수할 수 있도록, 필요한 최소한의 정보만 보여주고자 의도한 것이다. 결과적으로 책, 책의 판본, 저자및 다른 Key 정보를 저장할 것이다. 하지만 그외의 일반적인 도서관이 추가로 저장할만한 정보는 저장하지 않을 것이며, 여러개의 도서관 사이트를 지원하거나, "커다란 도서관"을 위한 기능은 제공하지 않을것이다.</em></p> + +<h2 id="개발중에_막혔어요_소스코드는_어딨죠">개발중에 막혔어요, 소스코드는 어딨죠?</h2> + +<p>튜토리얼을 진행하면서, 각 포인트마다 복사해서 붙여넣기할 수 있는 적절한 토막 코드가 제공될 것이다. 또한 당신이 스스로 (약간의 안내문과 함께) 도전해볼 수 있는 부분도 있을 것이다.</p> + +<p>개발중에 진행이 어렵다면, 여기<a href="https://github.com/mdn/django-locallibrary-tutorial"> Github</a>에 완전히 개발된 버전의 웹사이트 소스코드를 참고할 수도 있다.</p> + +<h2 id="요약">요약</h2> + +<p>LocalLibrary 웹사이트와 당신이 앞으로 배울 내용에 대해 좀 더 알게되었다. 이제 우리 예제를 담을 <a href="/ko/docs/Learn/Server-side/Django/skeleton_website">뼈대 프로젝트(skeleton project)</a>를 생성해볼 차례이다.</p> + +<p>{{PreviousMenuNext("Learn/Server-side/Django/development_environment", "Learn/Server-side/Django/skeleton_website", "Learn/Server-side/Django")}}</p> + + + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Server-side/Django/Introduction">Django introduction</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/development_environment">Setting up a Django development environment</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Django Tutorial: The Local Library website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django Tutorial Part 2: Creating a skeleton website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Models">Django Tutorial Part 3: Using models</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Admin_site">Django Tutorial Part 4: Django admin site</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django Tutorial Part 5: Creating our home page</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Generic_views">Django Tutorial Part 6: Generic list and detail views</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Sessions">Django Tutorial Part 7: Sessions framework</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Authentication">Django Tutorial Part 8: User authentication and permissions</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Forms">Django Tutorial Part 9: Working with forms</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Testing">Django Tutorial Part 10: Testing a Django web application</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Django Tutorial Part 11: Deploying Django to production</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/web_application_security">Django web application security</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></li> +</ul> diff --git a/files/ko/learn/server-side/django/web_application_security/index.html b/files/ko/learn/server-side/django/web_application_security/index.html new file mode 100644 index 0000000000..849f5bff3d --- /dev/null +++ b/files/ko/learn/server-side/django/web_application_security/index.html @@ -0,0 +1,176 @@ +--- +title: Django web application security +slug: Learn/Server-side/Django/web_application_security +translation_of: Learn/Server-side/Django/web_application_security +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Django/Deployment", "Learn/Server-side/Django/django_assessment_blog", "Learn/Server-side/Django")}}</div> + +<p class="summary">사용자의 데이터를 보호하는 것은 모든 웹사이트 개발에서 중요한 부분입니다. 우리는 이전의 강의 <a href="https://developer.mozilla.org/en-US/docs/Web/Security">Web security</a> 에서 자주 나타나는 보안 위협에 대해 알아봤습니다. — 이번 강의에서는 장고의 내장 보안 기능이 이런 위험에 어떻게 대처하는지 실제 예시들을 통해 살펴보겠습니다. </p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">이 문서를 보기 전에: </th> + <td>서버사이드 개발에 대한 "<a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/First_steps/Website_security">Website security</a>" 부분을 읽고 오세요. MDN 장고 튜토리얼에서 적어도 <a href="/en-US/docs/Learn/Server-side/Django/Forms">Django Tutorial Part 9: Working with forms</a> 까지는 모두 알고있어야 합니다. </td> + </tr> + <tr> + <th scope="row">목적: </th> + <td>장고 웹사이트의 보안을 위해 해야 하는 (하지 말아야 하는) 것들에 대해 이해해 봅시다. </td> + </tr> + </tbody> +</table> + +<h2 id="개요">개요</h2> + +<p><a href="https://developer.mozilla.org/en-US/docs/Web/Security">Website security</a> 문서는 서버사이드 설계에서 웹사이트 보안이란 무엇을 이야기하는건지, 또한 개발자가 막아내야 하는 몇가지 대표적인 위협에 대해 소개합니다. 이 문서에서 중요한 내용중의 하나는 바로 웹 애플리케이션이 브라우저에서 전송된 데이터를 신뢰하는 경우에는 거의 모든 종류의 공격이 가능하다는 것입니다. </p> + +<div class="warning"> +<p><strong>Important:</strong> 웹사이트 보안에 대해 당신이 배울 수 있는 가장 중요한 점 한가지는 <strong>브라우저의 데이터를 절대로 믿지 말라는 것</strong> 입니다. 이건 URL 파라미터의 <code>GET</code> request 데이터, <code>POST </code>데이터, HTTP 헤더와 쿠키, 사용자가 업로드한 파일들...기타등등을 포함합니다. 언제나 전송받는 모든 데이터를 의심하고 체크하십시오. 언제나 최악을 가정하십시오.</p> +</div> + +<p>Django 사용자들에게 좋은 소식은 대부분의 일반적인 위협들은 프레임워크에 의해 차단된다는 것입니다! <a href="https://docs.djangoproject.com/en/2.0/topics/security/">Security in Django</a> 문서는 Django의 보안 개요와 Django 기반의 웹사이트를 어떻게 지킬 수 있는지에 대해 설명하고 있습니다.</p> + +<h2 id="Common_threatsprotections">Common threats/protections</h2> + +<p>Django 문서를 여기로 복사해오기보다, 이 문서에서 우리는 Django <a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a> 튜토리얼에 있는 Django의 몇가지 보안 형태를 묘사해보도록 하겠습니다.</p> + +<h3 id="Cross_site_scripting_XSS">Cross site scripting (XSS)</h3> + +<p>XSS is a term used to describe a class of attacks that allow an attacker to inject client-side scripts <em>through</em> the website into the browsers of other users. This is usually achieved by storing malicious scripts in the database where they can be retrieved and displayed to other users, or by getting users to click a link that will cause the attacker’s JavaScript to be executed by the user’s browser.</p> + +<p>Django's template system protects you against the majority of XSS attacks by <a href="https://docs.djangoproject.com/en/2.0/ref/templates/language/#automatic-html-escaping">escaping specific characters</a> that are "dangerous" in HTML. We can demonstrate this by attempting to inject some JavaScript into our LocalLibrary website using the Create-author form we set up in <a href="/en-US/docs/Learn/Server-side/Django/Forms">Django Tutorial Part 9: Working with forms</a>.</p> + +<ol> + <li>Start the website using the development server (<code>python3 manage.py runserver</code>).</li> + <li>Open the site in your local browser and login to your superuser account.</li> + <li>Navigate to the author-creation page (which should be at URL: <code><a href="http://127.0.0.1:8000/catalog/author/create/">http://127.0.0.1:8000/catalog/author/create/</a></code>).</li> + <li>Enter names and date details for a new user, and then append the following text to the Last Name field:<br> + <code><script>alert('Test alert');</script></code>.<br> + <img alt="Author Form XSS test" src="https://mdn.mozillademos.org/files/14305/author_create_form_alert_xss.png" style="border-style: solid; border-width: 1px; height: 245px; width: 594px;"> + <div class="note"> + <p><strong>Note:</strong> This is a harmless script that, if executed, will display an alert box in your browser. If the alert is displayed when you submit the record then the site is vulnerable to XSS threats.</p> + </div> + </li> + <li>Press <strong>Submit</strong> to save the record.</li> + <li>When you save the author it will be displayed as shown below. Because of the XSS protections the <code>alert()</code> should not be run. Instead the script is displayed as plain text.<img alt="Author detail view XSS test" src="https://mdn.mozillademos.org/files/14307/author_detail_alert_xss.png" style="border-style: solid; border-width: 1px; height: 248px; width: 986px;"></li> +</ol> + +<p>If you view the page HTML source code, you can see that the dangerous characters for the script tags have been turned into their harmless escape code equivalents (e.g. <code>></code> is now <code>&gt;</code>)</p> + +<pre class="brush: html notranslate"><h1>Author: Boon&lt;script&gt;alert(&#39;Test alert&#39;);&lt;/script&gt;, David (Boonie) </h1> +</pre> + +<p>Using Django templates protects you against the majority of XSS attacks. However it is possible to turn off this protection, and the protection isn't automatically applied to all tags that wouldn't normally be populated by user input (for example, the <code>help_text</code> in a form field is usually not user-supplied, so Django doesn't escape those values).</p> + +<p>It is also possible for XSS attacks to originate from other untrusted source of data, such as cookies, Web services or uploaded files (whenever the data is not sufficiently sanitized before including in a page). If you're displaying data from these sources, then you may need to add your own sanitisation code.</p> + +<h3 id="Cross_site_request_forgery_CSRF_protection">Cross site request forgery (CSRF) protection</h3> + +<p>CSRF attacks allow a malicious user to execute actions using the credentials of another user without that user’s knowledge or consent. For example consider the case where we have a hacker who wants to create additional authors for our LocalLibrary.</p> + +<div class="note"> +<p><strong>Note:</strong> Obviously our hacker isn't in this for the money! A more ambitious hacker could use the same approach on other sites to perform much more harmful tasks (e.g. transfer money to their own accounts, etc.)</p> +</div> + +<p>In order to do this, they might create an HTML file like the one below, which contains an author-creation form (like the one we used in the previous section) that is submitted as soon as the file is loaded. They would then send the file to all the Librarians and suggest that they open the file (it contains some harmless information, honest!). If the file is opened by any logged in librarian, then the form would be submitted with their credentials and a new author would be created.</p> + +<pre class="brush: html notranslate"><html> +<body onload='document.EvilForm.submit()'> + +<form action="http://127.0.0.1:8000/catalog/author/create/" method="post" name='EvilForm'> + <table> + <tr><th><label for="id_first_name">First name:</label></th><td><input id="id_first_name" maxlength="100" name="first_name" type="text" value="Mad" required /></td></tr> + <tr><th><label for="id_last_name">Last name:</label></th><td><input id="id_last_name" maxlength="100" name="last_name" type="text" value="Man" required /></td></tr> + <tr><th><label for="id_date_of_birth">Date of birth:</label></th><td><input id="id_date_of_birth" name="date_of_birth" type="text" /></td></tr> + <tr><th><label for="id_date_of_death">Died:</label></th><td><input id="id_date_of_death" name="date_of_death" type="text" value="12/10/2016" /></td></tr> + </table> + <input type="submit" value="Submit" /> +</form> + +</body> +</html> +</pre> + +<p>Run the development web server, and log in with your superuser account. Copy the text above into a file and then open it in the browser. You should get a CSRF error, because Django has protection against this kind of thing!</p> + +<p>The way the protection is enabled is that you include the <code>{% csrf_token %}</code> template tag in your form definition. This token is then rendered in your HTML as shown below, with a value that is specific to the user on the current browser.</p> + +<pre class="brush: html notranslate"><input type='hidden' name='csrfmiddlewaretoken' value='0QRWHnYVg776y2l66mcvZqp8alrv4lb8S8lZ4ZJUWGZFA5VHrVfL2mpH29YZ39PW' /> +</pre> + +<p>Django generates a user/browser specific key and will reject forms that do not contain the field, or that contain an incorrect field value for the user/browser.</p> + +<p>To use this type of attack the hacker now has to discover and include the CSRF key for the specific target user. They also can't use the "scattergun" approach of sending a malicious file to all librarians and hoping that one of them will open it, since the CSRF key is browser specific.</p> + +<p>Django's CSRF protection is turned on by default. You should always use the <code>{% csrf_token %}</code> template tag in your forms and use <code>POST</code> for requests that might change or add data to the database.</p> + +<h3 id="Other_protections">Other protections</h3> + +<p>Django also provides other forms of protection (most of which would be hard or not particularly useful to demonstrate):</p> + +<dl> + <dt>SQL injection protection</dt> + <dd>SQL injection vulnerabilities enable malicious users to execute arbitrary SQL code on a database, allowing data to be accessed, modified, or deleted irrespective of the user's permissions. In almost every case you'll be accessing the database using Django’s querysets/models, so the resulting SQL will be properly escaped by the underlying database driver. If you do need to write raw queries or custom SQL then you'll need to explicitly think about preventing SQL injection.</dd> + <dt>Clickjacking protection</dt> + <dd>In this attack a malicious user hijacks clicks meant for a visible top level site and routes them to a hidden page beneath. This technique might be used, for example, to display a legitimate bank site but capture the login credentials in an invisible <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe" title="The HTML Inline Frame Element (<iframe>) represents a nested browsing context, effectively embedding another HTML page into the current page. In HTML 4.01, a document may contain a head and a body or a head and a frameset, but not both a body and a frameset. However, an <iframe> can be used within a normal document body. Each browsing context has its own session history and active document. The browsing context that contains the embedded content is called the parent browsing context. The top-level browsing context (which has no parent) is typically the browser window."><code><iframe></code></a> controlled by the attacker. Django contains <a href="https://docs.djangoproject.com/en/2.0/ref/clickjacking/#clickjacking-prevention">clickjacking protection</a> in the form of the <a href="https://docs.djangoproject.com/en/2.0/ref/middleware/#django.middleware.clickjacking.XFrameOptionsMiddleware" title="django.middleware.clickjacking.XFrameOptionsMiddleware"><code>X-Frame-Options middleware</code></a> which, in a supporting browser, can prevent a site from being rendered inside a frame.</dd> + <dt>Enforcing SSL/HTTPS</dt> + <dd>SSL/HTTPS can be enabled on the web server in order to encrypt all traffic between the site and browser, including authentication credentials that would otherwise be sent in plain text (enabling HTTPS is highly recommended). If HTTPS is enabled then Django provides a number of other protections you can use:</dd> +</dl> + +<ul> + <li><a href="https://docs.djangoproject.com/en/2.0/ref/settings/#std:setting-SECURE_PROXY_SSL_HEADER"><code>SECURE_PROXY_SSL_HEADER</code></a> can be used to check whether content is secure, even if it is incoming from a non-HTTP proxy.</li> + <li><a href="https://docs.djangoproject.com/en/2.0/ref/settings/#std:setting-SECURE_SSL_REDIRECT"><code>SECURE_SSL_REDIRECT</code></a> is used to redirect all HTTP requests to HTTPS.</li> + <li>Use <a href="https://docs.djangoproject.com/en/2.0/ref/middleware/#http-strict-transport-security">HTTP Strict Transport Security</a> (HSTS). This is an HTTP header that informs a browser that all future connections to a particular site should always use HTTPS. Combined with redirecting HTTP requests to HTTPS, this setting ensures that HTTPS is always used after a successful connection has occurred. HSTS may either be configured with <a href="https://docs.djangoproject.com/en/2.0/ref/settings/#std:setting-SECURE_HSTS_SECONDS"><code>SECURE_HSTS_SECONDS</code></a> and <a href="https://docs.djangoproject.com/en/2.0/ref/settings/#std:setting-SECURE_HSTS_INCLUDE_SUBDOMAINS"><code>SECURE_HSTS_INCLUDE_SUBDOMAINS</code></a> or on the Web server.</li> + <li>Use ‘secure’ cookies by setting <a href="https://docs.djangoproject.com/en/2.0/ref/settings/#std:setting-SESSION_COOKIE_SECURE"><code>SESSION_COOKIE_SECURE</code></a> and <a href="https://docs.djangoproject.com/en/2.0/ref/settings/#std:setting-CSRF_COOKIE_SECURE"><code>CSRF_COOKIE_SECURE</code></a> to <code>True</code>. This will ensure that cookies are only ever sent over HTTPS.</li> +</ul> + +<dl> + <dt>Host header validation</dt> + <dd>Use <a href="https://docs.djangoproject.com/en/2.0/ref/settings/#std:setting-ALLOWED_HOSTS"><code>ALLOWED_HOSTS</code></a> to only accept requests from trusted hosts.</dd> +</dl> + +<p>There are many other protections, and caveats to the usage of the above mechanisms. While we hope that this has given you an overview of what Django offers, you should still read the Django security documentation.</p> + +<ul> +</ul> + +<h2 id="Summary">Summary</h2> + +<p>Django has effective protections against a number of common threats, including XSS and CSRF attacks. In this article we've demonstrated how those particular threats are handled by Django in our <em>LocalLibrary</em> website. We've also provided a brief overview of some of the other protections.</p> + +<p>This has been a very brief foray into web security. We strongly recommend that you read <a href="https://docs.djangoproject.com/en/2.0/topics/security/">Security in Django</a> to gain a deeper understanding.</p> + +<p>The next and final step in this module about Django is to complete the <a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">assessment task</a>.</p> + +<h2 id="See_also">See also</h2> + +<ul> + <li><a href="https://docs.djangoproject.com/en/2.0/topics/security/">Security in Django</a> (Django docs)</li> + <li><a href="https://developer.mozilla.org/en-US/docs/Web/Security">Server side website security</a> (MDN)</li> + <li><a href="https://developer.mozilla.org/en-US/docs/Web/Security">Web security</a> (MDN)</li> + <li><a href="/en-US/docs/Web/Security/Securing_your_site">Securing your site</a> (MDN)</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Django/Deployment", "Learn/Server-side/Django/django_assessment_blog", "Learn/Server-side/Django")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Server-side/Django/Introduction">Django introduction</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/development_environment">Setting up a Django development environment</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Django Tutorial: The Local Library website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django Tutorial Part 2: Creating a skeleton website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Models">Django Tutorial Part 3: Using models</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Admin_site">Django Tutorial Part 4: Django admin site</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django Tutorial Part 5: Creating our home page</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Generic_views">Django Tutorial Part 6: Generic list and detail views</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Sessions">Django Tutorial Part 7: Sessions framework</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Authentication">Django Tutorial Part 8: User authentication and permissions</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Forms">Django Tutorial Part 9: Working with forms</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Testing">Django Tutorial Part 10: Testing a Django web application</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Django Tutorial Part 11: Deploying Django to production</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/web_application_security">Django web application security</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django mini blog</a></li> +</ul> diff --git a/files/ko/learn/server-side/express_nodejs/index.html b/files/ko/learn/server-side/express_nodejs/index.html new file mode 100644 index 0000000000..453d7490f0 --- /dev/null +++ b/files/ko/learn/server-side/express_nodejs/index.html @@ -0,0 +1,63 @@ +--- +title: Express 웹 프레임워크 (Node.js/JavaScript의 활용) +slug: Learn/Server-side/Express_Nodejs +tags: + - Express + - node.js + - 서버 + - 시작 + - 웹프레임워크 + - 자바스크립트 + - 초보개발자 +translation_of: Learn/Server-side/Express_Nodejs +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">Express는 JavaScript로 작성되고 Node.js 런타임 환경에서 구동되는 인기 있는 웹 프레임워크입니다. 이 장에서는 Express 프레임워크의 몇 가지 장점과 개발환경 설치 방법, 웹 개발과 배포작업의 방법을 다룹니다.</p> + +<h2 id="알아야할_것들">알아야할 것들</h2> + +<p>이 장의 내용은 Server-side 웹 프로그래밍과 웹 프레임워크에 대한 이해가 필요합니다. 잘 모르겠다면 <a href="/ko/docs/Learn/Server-side/First_steps">Server-side website programming first steps</a> 을 먼저 확인해보세요. 일반적인 프로그래밍 컨셉과 <a href="/ko/docs/Web/JavaScript">JavaScript</a> 의 지식이 요구되지만, 핵심까지 세세하게 알 필요는 없습니다.</p> + +<div class="note"> +<p><strong>Note</strong>: 여기서는 클라이언트 측에서의 자바스크립에 관한 많은 유용한 자료들을 이용할 수 있다. <a href="/ko/docs/Web/JavaScript">JavaScript</a>, <a href="/en-US/docs/Web/JavaScript/Guide">JavaScript Guide</a>, <a href="/en-US/docs/Learn/Getting_started_with_the_web/JavaScript_basics">JavaScript Basics</a>, <a href="/en-US/docs/Learn/JavaScript">JavaScript</a> (한 번 배워보자). 자바스크립트의 핵심과 컨셉은 Node.js를 이용한 서버측 개발과 같으므로, 여기의 자료들을 이용하는 게 좋을 것이다. Node.js 는HTTP서버를 구축하고 파일 시스템에 접근하는 등의 브라우저가 필요없는 환경에서에서 유용한 기능을 제공하는 <a href="https://nodejs.org/dist/latest-v6.x/docs/api/documentation.htm">additional APIs</a>를 제공하지만, 브라우저나 DOM에서 작동되는 자바스크립트 API는 지원하지 않는다.</p> + +<p>다음 목차에서는 Node.js와 Express 그리고 인터넷과 책에서의 방대한 좋은 자료들에 있는 정보들을 알려준다. 이들은 <a href="http://stackoverflow.com/a/5511507/894359">How do I get started with Node.js</a> (StackOverflow) 나 <a href="https://www.quora.com/What-are-the-best-resources-for-learning-Node-js?">What are the best resources for learning Node.js?</a> (Quora)에 참고해보자</p> +</div> + +<h2 id="목차">목차</h2> + +<dl> + <dt><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction">Express/Node introduction</a></dt> + <dd>처음으로 Express에 배우는 이 곳에서는 "Node가 뭐지?", "Express는 뭐지?"의 물음에 답하고, Express 웹 프레임워크의 전반적인 사항에 대해 알아볼 것이다. 주된 내용의 뼈대를 완성하고, Express 어플리케이션을 하나하나씩 배워볼 것이다. (하지만, 이 곳에서는 아직 어디서 테스팅이 이루어질 지 개발 환경등에서는 다루지 않을 것이다.).</dd> + <dt><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/development_environment">Setting up a Node (Express) development environment</a></dt> + <dd>이제 Express가 어디에 이용되는지 알아볼 것이다. Windows, Linux(Ubuntu), Mac OS X에서 Node/Express의 개발환경을 구축하기 위한 방법도 살펴볼 것이다. 운영체제에 관계없이, 여기서는 Express 개발을 시작하기위해서 어떤 것이 필요한지도 알려준다.</dd> + <dt><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">Express Tutorial: The Local Library website</a></dt> + <dd>실질적인 튜토리얼에 해당하는 이번 수업에서는 어떤 것을 배우고 차후 수업에 필요한 "로컬 라이브러리"에서의 웹사이트의 전반적인 개요도 알아본다.</dd> + <dt><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website">Express Tutorial Part 2: Creating a skeleton website</a></dt> + <dd>여기서는 웹사이트의 뼈대를 구성해 나갈 것이다. 웹사이트의 뼈대란 사이트의 사이트맵, 템플릿 및 데이터베이스등을 말하므로 이를 만들어볼 것이다.</dd> + <dt><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/mongoose">Express Tutorial Part 3: Using a Database (with Mongoose)</a></dt> + <dd>여기서는 간단하게나마 Node/Express에 필요한 데이터베이스의 개요에 대해 소개할 것이다. 그리고 로컬의 웹사이트의 DB에 접근하기 위해 <a href="http://mongoosejs.com/">Mongoose</a>를 사용하는 법도 알아본다. DB에서의 스키마와 모델이 어떻게 정의되는지, 필드의 타입과 기본적인 유효성에 대해서도 알아본다. 또한, 짧게나마 모델 데이터를 접근하는 주된 방법도 알아본다.</dd> + <dt><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/routes">Express Tutorial Part 4: Routes and controllers</a></dt> + <dd>이 수업에서는 <em>LocalLibray </em>웹사이트에 사용하기 위해 "더미" 핸들러 함수를 통한 라우터(URL 핸들링 코드)에 대해 배운다. 여러분의 라우팅 핸들링 코드를 사용할 수 있는 모듈 구조를 가지고 있으며, 다음 장에서 실제로 핸들러 기능을 확장할 수 있게 된다. 또한, Express에서 사용가능한 모듈 형식의 라우팅에 대해 쉽게 이해할 수 있을 것이다.</dd> + <dt><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express Tutorial Part 5: Displaying library data</a></dt> + <dd>자, 이제 웹사이트에 책이나 데이터들을 표시할 페이지를 추가할 수 있다. 페이지에는 사이트에 관련된 자세한 부분과 리스트 및 모델 타입들이 얼마나 많이 기록되는지에 관한 홈 페이지가 포함되어 있다. 따라서 우리들은 데이터베이스에서 기록을 얻고 템플릿을 사용하는 데 실질적인 경험을 가질 수 있다.</dd> + <dt><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms">Express Tutorial Part 6: Working with forms</a></dt> + <dd>이 수업에서는 Pug를 사용해서 어떻게 Express에서 <a href="/en-US/docs/Web/Guide/HTML/Forms">HTML Forms</a> 이 사용되는지 보여주고, 특히 데이터베이스에서 폼을 작성하고 업데이트하고 지우기 위해 사용하는 방법에 대해 배울 것이다.</dd> + <dt><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/deployment">Express Tutorial Part 7: Deploying to production</a></dt> + <dd>이제 꽤 훌륭한 로컬라이브러리 웹사이트 만들 수 있으며 , 웹 서버에 업로드 함으로서 여러 사람들이 인터넷을 통해 접근할 수 있게 만들 수 있다. 이 수업은 전반적으로 웹 사이트를 배포하기 위해 호스트와 연결하는 등을 배우고, 실제 서비스를 하기위해 준비해야할 것들을 알려 준다.</dd> +</dl> + +<h2 id="튜토리얼_추가하기">튜토리얼 추가하기</h2> + +<p><strong>자습서의 끝입니다. </strong>(지금은 말이죠). 만약 이 자습서의 내용을 보충하고 싶으시다면 아래와 같은 주제를 해 주시면 좋을 것 같네요:</p> + +<ul> + <li>세션 이용하기</li> + <li>사용자 인증</li> + <li>사용자 권한 부여 및 허가</li> + <li>Express 웹 어플리케이션 테스트</li> + <li>Express 웹 어플리케이션 보안</li> +</ul> + +<p>그리고 평가 작업도 있으면 정말 좋을 것 같아요!</p> diff --git a/files/ko/learn/server-side/express_nodejs/introduction/index.html b/files/ko/learn/server-side/express_nodejs/introduction/index.html new file mode 100644 index 0000000000..caa4eb8eaa --- /dev/null +++ b/files/ko/learn/server-side/express_nodejs/introduction/index.html @@ -0,0 +1,488 @@ +--- +title: Express/Node 소개 +slug: Learn/Server-side/Express_Nodejs/Introduction +translation_of: Learn/Server-side/Express_Nodejs/Introduction +--- +<div>{{LearnSidebar}}</div> + +<div>{{NextMenu("Learn/Server-side/Express_Nodejs/development_environment", "Learn/Server-side/Express_Nodejs")}}</div> + +<p class="summary">첫번째 Express 수업에서는 Node, Express를 알아보고, Express 웹 프레임워크 제작의 전반에 대해 배우게 됩니다.<br> + 우선 주요 특징들에 대한 틀을 정리한 후 Express 어플리케이션을 구성하는 주요 구성요소들을 살펴볼 것입니다. (테스트할 개발환경은 아직이겠지만요)</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">알아야 할 것들</th> + <td>기본적인 컴퓨터의 이해. 서버 사이드 웹사이트 프로그래밍(<a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/First_steps">server-side website programming</a>), 그리고 특별히 웹사이트에서 클라이언트와 서버간의 상호작용(<a href="/en-US/docs/Learn/Server-side/First_steps/Client-Server_overview">client-server interactions in websites</a>)의 메커니즘에 대한 이해</td> + </tr> + <tr> + <th scope="row">목표</th> + <td>Express에 익숙해지고, Node와 어떻게 함께 사용되는지, 기능은 어떠한지, 그리고 Express 어플리케이션의 주요한 구성요소들에 대해 배운다.</td> + </tr> + </tbody> +</table> + +<h2 id="Express와_Node란">Express와 Node란?</h2> + +<p><a href="https://nodejs.org/">Node</a> (또는 더 공식적으로는 Node.js) 는 오픈소스, 크로스 플랫폼이며, 개발자가 모든 종류의 서버 사이드 도구들과 어플리케이션을 <a href="/en-US/docs/Glossary/JavaScript">JavaScript</a>로 만들수 있도록 해주는 런타임 환경이다.런타임은 브라우져 영역 밖에서도 사용할수 있도록 의도했다.(예를들면 서버 OS 또는 컴퓨터에서 직접적으로 실행되는). 이와 같이, 이 환경에서 특정 브라우져에서의 자바스트립트 API들을 제외시키고 , HTTP 와 파일 시스템 라이브러리들을 포함하여 더 많은 전형적인 OS API들을 추가했다.</p> + +<p>웹 서버 관점에서 노드는 많은 장점들을 가진다:</p> + +<ul> + <li>훌륭한 퍼포먼스! Node는 단위시간당 처리량과 어플리케이션에서 확장성을 최적화 시키고, 많은 공통적인 웹 개발 문제들을 맞먹는다.(예를들면 실시간 웹 어플리케이션들)</li> + <li>코드는 순수한 자바스크립트로 작성된다, 이는 당신이 각각 브라우져와 웹 서버 코드를 작성할때 언어들 사이에 "context shift" 를 다루는 시간을 적게 할수 있을을 의미한다.</li> + <li>자바스크립트는 비교적 새로운 프로그래밍 언어이고 또다른 전통적인 웹서버 언어들과 비교할때 언어적 설계에서 향상의 이득을 가진다. 많은 다른 새롭거나 인기있는 언어들은 자바스크립트로 컴파일하거나 변환한다 그래서 또한 당신은 커피스크립트, 클로져스크립트, 스칼라, 라이브 스크립트 등등을 사용할 수 있다.</li> + <li>노드 패키지 매니저(NPM)는 수천만개의 재사용가능한 패키지에 접근할 수 있도록 한다. 이것은 최고의 의존성 해결과 또한 수많은 빌드 툴체인이 자동화되도록 한다.</li> + <li>이것은 마이크로소프트 윈도우, OS X, 룩스, 솔라리스, FreeBSD, OpenBSD, WebOS, 그리고 NonStop OS 등에서 돌아가는 버전과 같이 포터플하다. 더군다나, 이것은 특정한 인프라구조를 지원하고 Node 사이트 호스팅을 위한 문서를 제공하는 많은 웹 호스팅 공급자들에 의해서 잘 지원되고 있다.</li> + <li>도움을 주고자 하는 수많은 사람들이 존재하는 아주 활발한 개발 생태계와 커뮤니티를 지니고 있다.</li> +</ul> + +<h3 id="Hello_Node.js">Hello Node.js</h3> + +<p>아래 코드처럼 Node에 HTTP 모듈을 사용하여 모든 요청에 응답이 가능한 간단한 웹 서버를 쉽게 생성할 수 있습니다.</p> + +<p>이렇게하면 웹 서버가 만들어지고 URL <code>http://127.0.0.1:8000/</code> 에 있는 모든 종류의 HTTP 요청에 수신하게 됩니다. 요청이 하나 들어왔을 때, "Hello World" 텍스트 응답을 보내도록 하겠습니다.</p> + +<ol> + <li>터미널을 연다. (윈도우에서는, 커맨드라인 유틸리티)<br> + ※ 윈도우 키 + R => 'CMD'</li> + <li>프로그램을 저장할 폴더를 생성하고(여기서는 <code>test-node</code>), 아래 명령을 입력하여 해당 폴더로 이동한다.</li> +</ol> + +<pre class="notranslate">cd test-node</pre> + +<ol start="3"> + <li>즐겨쓰는 텍스트에디터를 열어 아래 코드를 입력한 후, 파일명 <code>hello.js</code> 로 저장한다.</li> +</ol> + +<pre class="brush: js notranslate">//Load HTTP module +var http = require("http"); + +//Create HTTP server and listen on port 8000 for requests +http.createServer(function (request, response) { + + // Set the response HTTP header with HTTP status and Content type + response.writeHead(200, {'Content-Type': 'text/plain'}); + + // Send the response body "Hello World" + response.end('Hello World\n'); +}).listen(8000); + +// Print URL for accessing server +console.log('Server running at http://127.0.0.1:8000/')</pre> + +<p>4. 터미널로 돌아가 아래 명령을 입력한다.</p> + +<pre class="brush: bash notranslate">node hello.js</pre> + +<p>이제, 웹브라우저를 열어 다음 주소로 이동한다. <code>http://localhost:8000</code> 곧바로 좌상단에 "<strong>Hello World</strong>" 문구가 있고, 나머지 영역은 비어있는 웹페이지를 볼 수 있다.</p> + +<p>Node 자체가 다른 일반적인 웹 개발 기능을 지원하지 않습니다. 만약 다른 HTTP 패턴 (예 : <code>GET</code>, <code>POST</code>, <code>DELETE</code> 등)에 대한 특정 처리를 추가하려면 서로 다른 URL 경로("routes")를 사용하여 요청을 개별적으로 처리, 정적 파일을 제공, 템플릿을 사용하여 동적으로 응답을 생성할 수 있으며, 코드를 직접 작성할 필요가가 생기게 됩니다. 또는 기본적인 것들을 직접 구현하는 작업을 피하고 웹 프레임 워크를 사용할 수 있습니다! </p> + +<p><a href="https://expressjs.com/">Express</a> 는 가장 인기있는 Node 웹 프레임 워크 이며, 다른 많은 인기있는 <a href="https://expressjs.com/en/resources/frameworks.html">Node web frameworks</a>의 기본 라이브러리 입니다. Express는 다음과 같은 메커니즘을 제공합니다:</p> + +<ul> + <li>HTTP 통신 요청(Request; GET, POST, DELETE 등)에 대한 핸들러를 만든다.</li> + <li>템플릿에 데이터를 넣어 응답(response)을 만들기 위해 view의 렌더링 엔진과 결합(integrate)한다. </li> + <li>접속을 위한 포트나 응답 렌더링을 위한 템플릿 위치같은 공통 웹 어플리케이션 세팅을 한다. </li> + <li>핸들링 파이프라인(reqest handling pipeline) 중 필요한 곳에 추가적인 미들웨어 처리 요청을 추가한다.</li> +</ul> + +<p><em>Express</em> 자체는 꽤나 최소한의 기능만 탑재하지만 개발자들이 거의 모든 웹 개발의 문제를 다루는 호환성있는 미들웨어 패키지를 만들어왔습니다. 쿠키, 세션, 사용자 로그인, URL 파라미터, <code>POST</code> 데이터, 보안 헤더와 그외 많은 것들에 대한 라이브러리들이 있습니다. 여러분은 <a href="http://expressjs.com/en/resources/middleware.html">Express Middleware</a>에서 Express 팀이 유지보수하는 미들웨어 패키지 리스트를 확인할 수 있습니다. (유명한 서드파티 패키지들을 포함).</p> + +<div class="note"> +<p><strong>Note:</strong> This flexibility is a double edged sword. There are middleware packages to address almost any problem or requirement, but working out the right packages to use can sometimes be a challenge. There is also no "right way" to structure an application, and many examples you might find on the Internet are not optimal, or only show a small part of what you need to do in order to develop a web application.</p> +</div> + +<h2 id="유래">유래</h2> + +<p>노드(Node)는 2009년 리눅스 한정으로 배포 되었다. NPM은 2010년에 배포되었고, 네이티브 윈도우즈(Windows)는 2012년부터 지원하기 시작하였다. 현재 배포중인 최신 LTS 버전은 Node v8.9.3이 있고, 가장 최신 버전은 Node 9 이다. 이것은 유구한 역사를 짧게 적어본 것으로 더 알고 싶다면 <a href="https://ko.wikipedia.org/wiki/Node.js">위키페디아</a>를 참조하면 된다.</p> + +<p>Express는 2010년 11월 처음 배포되었고 현재는 4.16 버전이 되었다. 현재 배포 버전과의 변경사항을 알고 싶다면 <a href="https://expressjs.com/en/changelog/4x.html">changelog</a> 를 확인하면 된다. 그리고 더 자세한 역사와 릴리즈 노트는 <a href="https://github.com/expressjs/express/blob/master/History.md">GitHub</a> 를 참조하면 된다.</p> + +<h2 id="어떻게_NodeExpress가_유명해졌을까">어떻게 Node/Express가 유명해졌을까?</h2> + +<p>유명한 웹 프레임워크 쓴다는 것은 아주 중요합니다. 바로 해당 기술에 대한 지속가능성, 문서화, 추가 라이브러리, 그리고 기술 지원 자원에 대한 지표가 되기 때문입니다. </p> + +<p>There isn't any readily-available and definitive measurement of the popularity of server-side frameworks (although sites like <a href="http://hotframeworks.com/">Hot Frameworks</a> attempt to assess popularity using mechanisms like counting the number of GitHub projects and StackOverflow questions for each platform). A better question is whether Node and Express are "popular enough" to avoid the problems of unpopular platforms. Are they continuing to evolve? Can you get help if you need it? Is there an opportunity for you to get paid work if you learn Express?</p> + +<p>Based on the number of <a href="https://expressjs.com/en/resources/companies-using-express.html">high profile companies</a> that use Express, the number of people contributing to the codebase, and the number of people providing both free and paid for support, then yes, <em>Express</em> is a popular framework!</p> + +<h2 id="Express는_개발이_자유로울까">Express는 개발이 자유로울까?</h2> + +<p>Web frameworks often refer to themselves as "opinionated" or "unopinionated".</p> + +<p>Opinionated frameworks are those with opinions about the "right way" to handle any particular task. They often support rapid development <em>in a particular domain </em>(solving problems of a particular type) because the right way to do anything is usually well-understood and well-documented. However they can be less flexible at solving problems outside their main domain, and tend to offer fewer choices for what components and approaches they can use.</p> + +<p>Unopinionated frameworks, by contrast, have far fewer restrictions on the best way to glue components together to achieve a goal, or even what components should be used. They make it easier for developers to use the most suitable tools to complete a particular task, albeit at the cost that you need to find those components yourself.<br> + <br> + Express is unopinionated. You can insert almost any compatible middleware you like into the request handling chain, in almost any order you like. You can structure the app in one file or multiple files, and using any directory structure. You may sometimes feel that you have too many choices!</p> + +<h2 id="Express의_코드는_어떻게_생겼을까">Express의 코드는 어떻게 생겼을까?</h2> + +<p>In a traditional data-driven website, a web application waits for HTTP requests from the web browser (or other client). When a request is received the application works out what action is needed based on the URL pattern and possibly associated information contained in <code>POST</code> data or <code>GET</code> data. Depending on what is required it may then read or write information from a database or perform other tasks required to satisify the request. The application will then return a response to the web browser, often dynamically creating an HTML page for the browser to display by inserting the retrieved data into placeholders in an HTML template.</p> + +<p>Express provides methods to specify what function is called for a particular HTTP verb (<code>GET</code>, <code>POST</code>, <code>SET</code>, etc.) and URL pattern ("Route"), and methods to specify what template ("view") engine is used, where template files are located, and what template to use to render a response. You can use Express middleware to add support for cookies, sessions, and users, getting <code>POST</code>/<code>GET</code> parameters, etc. You can use any database mechanism supported by Node (Express does not define any database-related behaviour).</p> + +<p>The following sections explain some of the common things you'll see when working with <em>Express</em> and <em>Node</em> code.</p> + +<h3 id="Helloworld_Express">Helloworld Express</h3> + +<p>First lets consider the standard Express <a href="https://expressjs.com/en/starter/hello-world.html">Hello World</a> example (we discuss each part of this below, and in the following sections).</p> + +<div class="note"> +<p><strong>Tip:</strong> If you have Node and Express already installed (or if you install them as shown in the <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/development_environment">next article</a>), you can save this code in a file called <strong>app.js</strong> and run it in a command prompt by calling <code>node app.js</code>.</p> +</div> + +<pre class="brush: js notranslate">var express = require('express'); +var app = express(); + +<strong>app.get('/', function (req, res) { + res.send('Hello World!'); +});</strong> + +app.listen(3000, function () { + console.log('Example app listening on port 3000!'); +}); +</pre> + +<p>The first two lines <code>require()</code> (import) the express module and create an <a href="https://expressjs.com/en/4x/api.html#app">Express application</a>. This object, which is traditionally named <code>app</code>, has methods for routing HTTP requests, configuring middleware, rendering HTML views, registering a template engine, and modifying <a href="https://expressjs.com/en/4x/api.html#app.settings.table">application settings</a> that control how the application behaves (e.g. the environment mode, whether route definitions are case sensitive, etc.)</p> + +<p>The middle part of the code (the three lines starting with <code>app.get</code>) shows a <em>route definition</em>. The <code>app.get()</code> method specifies a callback function that will be invoked whenever there is an HTTP <code>GET</code> request with a path (<code>'/'</code>) relative to the site root. The callback function takes a request and a response object as arguments, and simply calls <code><a href="https://expressjs.com/en/4x/api.html#res.send">send()</a></code> on the response to return the string "Hello World!"</p> + +<p>The final block starts up the server on port '3000' and prints a log comment to the console. With the server running, you could go to <code>localhost:3000</code> in your browser to see the example response returned.</p> + +<h3 id="모듈의_생성과_불러옴Importing_and_creating_modules">모듈의 생성과 불러옴(Importing and creating modules)</h3> + +<p>A module is a JavaScript library/file that you can import into other code using Node's <code>require()</code> function. <em>Express</em> itself is a module, as are the middleware and database libraries that we use in our <em>Express</em> applications.</p> + +<p>The code below shows how we import a module by name, using the <em>Express</em> framework as an example. First we invoke the <code style="font-style: normal; font-weight: normal;">require()</code> function, specifying the name of the module as a string (<code>'express'</code>), and calling the returned object to create an <a href="https://expressjs.com/en/4x/api.html#app">Express application</a>. We can then access the properties and functions of the application object.</p> + +<pre class="brush: js notranslate">var express = require('express'); +var app = express(); +</pre> + +<p>You can also create your own modules that can be imported in the same way.</p> + +<div class="note"> +<p><strong>Tip:</strong> You will <em>want </em>to create your own modules, because this allows you to organise your code into managable parts — a monolithic single-file application is hard to understand and maintain. Using modules also helps you manage your namespace, because only the variables you explicitly export are imported when you use a module.</p> +</div> + +<p>To make objects available outside of a module you just need to assign them to the <code>exports</code> object. For example, the <strong>square.js</strong> module below is a file that exports <code>area()</code> and <code>perimeter()</code> methods:</p> + +<pre class="brush: js notranslate">exports.area = function (width) { return width * width; }; +exports.perimeter = function (width) { return 4 * width; }; +</pre> + +<p>We can import this module using <code>require()</code>, and then call the exported method(s) as shown:</p> + +<pre class="brush: js notranslate">var square = require('./square'); // Here we require() the name of the file without the (optional) .js file extension +console.log('The area of a square with a width of 4 is ' + square.area(4));</pre> + +<div class="note"> +<p><strong>Note:</strong> You can also specify an absolute path to the module (or a name, as we did initially).</p> +</div> + +<p>If you want to export a complete object in one assignment instead of building it one property at a time, assign it to <code>module.exports</code> as shown below (you can also do this to make the root of the exports object a constructor or other function):</p> + +<pre class="brush: js notranslate">module.exports = { + area: function(width) { + return width * width; + }, + + perimeter: function(width) { + return 4 * width; + } +}; +</pre> + +<p>For a lot more information about modules see <a href="https://nodejs.org/api/modules.html#modules_modules">Modules</a> (Node API docs).</p> + +<h3 id="비동기식_API의_사용">비동기식 API의 사용</h3> + +<p>JavaScript 코드는 완료까지 시간이 다소 소요될 수 있는 작업에 대해 동기보다 비동기 API를 자주 사용합니다. 동기 API는 다음 작업이 시작하기 전에 각 작업이 완료되어야만 합니다. 예를 들어, 다음의 로그함수들은 동기식이며 텍스트를 순서대로 콘솔에 나타낼 것입니다.(First, Second)</p> + +<pre class="brush: js notranslate">console.log('First'); +console.log('Second');</pre> + +<p>반면 비동기 API는 API가 작업을 시작하고, 즉시 반환(작업이 완료되기 전에)합니다. 작업이 완료되면 API는 추가적인 작업 수행을 위한 일부 매커니즘을 사용합니다. 예를 들어 아래의 코드는 "Second, First"를 출력합니다. 그 이유는 <code>setTimeout()</code> 메서드가 먼저 호출되고 즉시 반환되더라도, 작업이 몇 초 동안 완료되지 않기 때문입니다.</p> + +<pre class="brush: js notranslate">setTimeout(function() { + console.log('First'); + }, 3000); +console.log('Second'); +</pre> + +<p>Node는 싱글 스레드 이벤트 기반 환경이기 때문에 non-blocking 비동기 API는 브라우저보다 Node에서 훨씬 더 중요합니다.</p> + +<p>'싱글 스레드'는 서버에 모든 요청이 별도의 프로세스로 생성되지 않고 동일한 스레드에서 실행되는 것을 의미합니다. 이 모델은 속도와 서버 리소스 측면에서 아주 효율적이지만, 만약 특정 함수가 완료되는데에 오랜 시간이 걸리는 동기 메서드를 호출하는 함수가 있다면 현재 요청 뿐만 아니라 웹 어플리케이션에서 다른 요청이 처리되는 것도 차단합니다.</p> + +<p>비동기 API가 완료되었음을 어플리케이션에 알리는 방법은 여러가지가 있습니다. 가장 일반적인 방법은 비동기 API를 호출시 작업이 완료되면 다시 호출되는 콜백함수를 이용하는 것이며, 위의 예제에서 사용된 방식입니다.</p> + +<div class="note"> +<p><strong>Tip:</strong> 순서대로 수행해야하는 종속적인 비동기 작업들이 있을 경우, 콜백을 사용하는 것은 꽤 복잡할 수 있습니다. 중첩된 여러 단계의 콜백이 생성되기 때문입니다. 이 문제는 흔히 'callback hell'이라고 일컬어집니다. 이 문제는 good coding practices(<a href="http://callbackhell.com/">http://callbackhell.com/</a> 참고), <a href="https://www.npmjs.com/package/async">async</a>와 같은 모듈의 사용, <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise">Promises</a>와 같은 ES6 기능을 사용함으로써 개선될 수 있습니다.</p> +</div> + +<div class="note"> +<p><strong>Note:</strong> Node와 Express의 일반적인 규칙은 error-first callbacks을 사용하는 것입니다. 이 규칙에서 콜백 함수의 첫번 째 값은 에러값이고, 다음 인자에는 성공 데이터가 포함됩니다. 이 방법에 대한 좋은 설명은 이 블로그에서 확인할 수 있습니다.:: <a href="http://fredkschott.com/post/2014/03/understanding-error-first-callbacks-in-node-js/ ">The Node.js Way - Understanding Error-First Callbacks</a> (fredkschott.com).</p> +</div> + +<h3 id="라우트_핸들러의_사용">라우트 핸들러의 사용</h3> + +<p>In our <em>Hello World</em> Express example see above we defined a (callback) route handler function for HTTP <code>GET</code> requests to the site root (<code>'/'</code>).</p> + +<pre class="brush: js notranslate">app.<strong>get</strong>('/', function (req, res) { + res.send('Hello World!'); +}); +</pre> + +<p>The callback function takes a request and a response object as arguments. In this case the method simply calls <code><a href="https://expressjs.com/en/4x/api.html#res.send">send()</a></code> on the response to return the string "Hello World!" There are a <a href="https://expressjs.com/en/guide/routing.html#response-methods">number of other response methods</a> for ending the request/response cycle, for example you could call <code><a href="https://expressjs.com/en/4x/api.html#res.json">res.json()</a></code> to send a JSON response or <code><a href="https://expressjs.com/en/4x/api.html#res.sendFile">res.sendFile()</a></code> to send a file.</p> + +<div class="note"> +<p><strong>JavaScript tip:</strong> You can use any argument names you like in the callback functions; when the callback is invoked the first argument will always be the request and the second will always be the response. It makes sense to name them such that you can identify the object you're working with in the body of the callback.</p> +</div> + +<p>The <em>Express application</em> object also provides methods to define route handlers for all the other HTTP verbs, which are mostly used in exactly the same way: <code>post()</code>, <code>put()</code>, <code>delete()</code>, <code>options()</code>, <code>trace()</code>, <code>copy()</code>, <code>lock()</code>, <code>mkcol()</code>, <code>move()</code>, <code>purge()</code>, <code>propfind()</code>, <code>proppatch()</code>, <code>unlock()</code>, <code>report()</code>, <code>mkactivity()</code>, <code>checkout()</code>, <code>merge()</code>, <code>m-</code><code>search()</code>, <code>notify()</code>, <code>subscribe()</code>, <code>unsubscribe()</code>, <code>patch()</code>, <code>search()</code>, and <code>connect()</code>.</p> + +<p>There is a special routing method, <code>app.all()</code>, which will be called in response to any HTTP method. This is used for loading middleware functions at a particular path for all request methods. The following example (from the Express documentation) shows a handler that will be executed for requests to <code>/secret</code> irrespective of the HTTP verb used (provided it is supported by the <a href="https://nodejs.org/api/http.html#http_http_methods">http module</a>).</p> + +<pre class="brush: js notranslate">app.all('/secret', function (req, res, next) { + console.log('Accessing the secret section ...') + next() // pass control to the next handler +})</pre> + +<p>Routes allow you to match particular patterns of characters in a URL, and extract some values from the URL and pass them as parameters to the route handler (as attributes of the request object passed as a parameter).</p> + +<p>Often it is useful to group route handlers for a particular part of a site together and access them using a common route-prefix (e.g. a site with a Wiki might have all wiki-related routes in one file and have them accessed with a route prefix of <em>/wiki/</em>). In <em>Express</em> this is achieved by using the <code><a href="http://expressjs.com/en/guide/routing.html#express-router">express.Router</a></code> object. For example, we can create our wiki route in a module named <strong>wiki.js</strong>, and then export the <code>Router</code> object, as shown below:</p> + +<pre class="brush: js notranslate">// wiki.js - Wiki route module + +var express = require('express') +var router = express.Router() + +// Home page route +router.get('/', function (req, res) { + res.send('Wiki home page') +}) + +// About page route +router.get('/about', function (req, res) { + res.send('About this wiki') +}) + +module.exports = router +</pre> + +<div class="note"> +<p><strong>Note:</strong> Adding routes to the <code>Router</code> object is just like adding routes to the <code>app</code> object (as shown previously).</p> +</div> + +<p>To use the router in our main app file we would then <code>require()</code> the route module (<strong>wiki.js</strong>), then call <code>use()</code> on the <em>Express</em> application to add the Router to the middleware handling path. The two routes will then be accessible from <code style="font-style: normal; font-weight: normal;">/wiki/</code> and <code style="font-style: normal; font-weight: normal;">/wiki/about/</code>.</p> + +<pre class="brush: js notranslate">var wiki = require('./wiki.js') +// ... +app.use('/wiki', wiki)</pre> + +<p>We'll show you a lot more about working with routes, and in particular about using the <code>Router</code>, later on in the linked section<a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/routes"> Routes and controllers .</a></p> + +<h3 id="미들웨어의_사용">미들웨어의 사용</h3> + +<p>미들웨어는 정적 파일 제공에서 오류 처리, HTTP 응답 압축에 이르기까지 Express 앱에서 광범위하게 사용됩니다. 라우트 함수는 <font><font>HTTP 클라이언트에 일부 응답을 반환하여 HTTP 요청-응답주기를 종료하는 반면, 미들웨어 함수는 </font></font><em><font><font>일반적으로</font></font></em><font><font> 요청 또는 응답에 대해 일부 작업을 수행 한 다음 "스택"(이는 미들웨어 혹은 라우트 핸들러일 수 있습니다.)에서 다음 함수를 호출합니다. 미들웨어가 호출되는 순서는 앱 개발자에게 달려있습니다.</font></font></p> + +<div class="note"> +<p><strong>Note:</strong> <font><font>미들웨어는 모든 작업을 수행하고, 코드를 실행하고, 요청 및 응답 객체를 변경할 수 </font></font><em><font><font>있으며, 요청-응답주기를 종료</font></font></em><font><font> 할 </font><em><font>수도</font></em><font> 있습니다. 만약 주기가 종료되지 않으면, 다음 미들웨어 함수의 제어를 위해 <code>next()</code>를 호출해야합니다.( 혹은 요청이 중단된 상태로 유지될 것입니다.)</font></font></p> +</div> + +<p><font><font>대부분의 앱은 </font><font>쿠키, 세션, 사용자 인증,<code> POST</code>요청 </font><font>및 JSON 데이터 접근</font><font> </font><font>, logging 등과 </font><font>같은 일반적인 웹 개발 작업을 단순화하기 위해<em>서드파티</em></font></font><font><font> 미들웨어를 사용합니다 </font><font><a href="http://expressjs.com/en/resources/middleware.html" rel="noopener">. Express 팀에서 관리하는 미들웨어 패키지 목록을</a><font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);"> </span></font></font></font><font><font>이 곳에서 찾을 수 있습니다 </font><font>( 다른 인기있는 서드파티 패키지도 포함). </font><font>다른 Express 패키지는 NPM 패키지 관리자에서 사용할 수 있습니다.</font></font></p> + +<p><font><font>서드파티 미들웨어를 사용하려면 먼저 NPM을 사용하여 앱에 설치해야합니다. </font><font>예를 들어 </font></font><a href="http://expressjs.com/en/resources/middleware/morgan.html" rel="noopener"><font><font>morgan</font></font></a><font><font> HTTP 요청 logger 미들웨어 </font><font>를 설치하려면 다음과 </font><font>같이 진행합니다.</font></font></p> + +<pre class="brush: bash notranslate"><code>$ npm install morgan +</code></pre> + +<p>그런 다음 <em>Express application object에 </em>use()를 호출해서 스택에 이 미들웨어를 추가합니다.</p> + +<pre class="brush: js notranslate">var express = require('express'); +<strong>var logger = require('morgan');</strong> +var app = express(); +<strong>app.use(logger('dev'));</strong> +...</pre> + +<div class="note"> +<p><strong>Note:</strong> <font>미들웨어 및 라우팅 함수는 선언된 순서대로 호출됩니다. </font><font>일부 미들웨어의 경우 순서가 중요합니다 (예를 들어 세션 미들웨어가 쿠키 미들웨어에 의존하는 경우, 쿠키 핸들러를 먼저 추가해야합니다). 거의 항상 라우트를 설정하기 전에 미들웨어가 호출되거나, 미들웨어로 인해 추가된 기능에 라우트 핸들러가 접근할 수 없습니다.</font></p> +</div> + +<p><font><font>당신은 자신만의 미들웨어 함수를 작성할 수 있으며, 그렇게 해야 할 가능성이 높습니다 (에러 처리 코드를 생성하는 경우에만 해당). 미들웨어 함수와 라우트 핸들러 콜백 </font><font>의 </font></font><strong><font><font>유일한</font></font></strong><font><font> 차이점은 미들웨어 함수에 세 번째 인자로 미들웨어 함수가 </font></font><font><font>요청 주기를 완료하지 않을 때 호출되는 <code>next</code>가 있다는 것입니다. (미들웨어 함수가 호출 될 때 여기에는 반드시 호출되는 <em>next</em></font></font><font><font> 함수가 포함됩니다.).</font></font></p> + +<p><font><font>당신이 모든 응답 혹은 특정 HTTP 동사(</font></font><code>GET</code><font><font>, </font></font><code>POST</code> 등)에 미들웨어를 적용할지 여부에 따라<code>app.use()</code><font><font>또는 </font></font><code>app.add()</code>와 함께<font><font> 프로세싱 체인에 미들웨어 기능을 추가 할 수 있습니다. 두 경우 모두 라우트를 동일하게 지정하지만 </font></font><strong><font><font>app.use ()</font></font></strong><font><font> 호출시 라우트는 선택 사항 </font><font>입니다.</font></font></p> + +<p><font><font>아래의 예제는 두 가지 방법을 사용하고, 경로를 사용하거나 사용하지 않고 미들웨어 기능을 추가하는 방법을 보여줍니다.</font></font></p> + +<pre class="brush: js notranslate">var express = require('express') +var app = express() + +// An example middleware function +var a_middleware_function = function(req, res, <em>next</em>) { + //... perform some operations + next(); //Call next() so Express will call the next middleware function in the chain. +} + +// Function added with use() for all routes and verbs +app.use(a_middleware_function) + +//Function added with use() for a specific route +app.use('/someroute', a_middleware_function) + +// A middleware function added for a specific HTTP verb and route +app.get('/', a_middleware_function ) + +app.listen(3000)</pre> + +<div class="note"> +<p><strong>JavaScript Tip:</strong> <font>위에서 우리는 미들웨어 함수를 별도로 선언 한 다음 그것을 콜백으로 설정합니다. </font><font>이전 라우트 핸들러 함수에서는 우리는 콜백 함수가 사용될 때 선언했습니다. </font><font>JavaScript에서는 두 방법 모두 유효합니다.</font></p> +</div> + +<p><font><font>Express 공식 문서에는 </font><font>Express 미들웨어 </font></font><a href="https://expressjs.com/en/guide/using-middleware.html" rel="noopener"><font><font>사용</font></font></a><font><font> 및 </font></font><a href="http://expressjs.com/en/guide/writing-middleware.html" rel="noopener"><font><font>작성</font></font></a><font><font> 에 대한 훨씬 더 우수한 자료들이 </font><font>있습니다.</font></font></p> + +<h3 id="저장된_파일을_서버화하기">저장된 파일을 서버화하기</h3> + +<p>You can use the <a href="http://expressjs.com/en/4x/api.html#express.static">express.static</a> middleware to serve static files, including your images, CSS and JavaScript (<code>static()</code> is the only middleware function that is actually <strong>part</strong> of <em>Express</em>). For example, you would use the line below to serve images, CSS files, and JavaScript files from a directory named '<strong>public'</strong> at the same level as where you call node:</p> + +<pre class="brush: js notranslate">app.use(express.static('public')) +</pre> + +<p>Any files in the public directory are served by adding their filename (<em>relative</em> to the base "public" directory) to the base URL. So for example:</p> + +<pre class="notranslate"><code>http://localhost:3000/images/dog.jpg +http://localhost:3000/css/style.css +http://localhost:3000/js/app.js +http://localhost:3000/about.html +</code></pre> + +<p>You can call <code>static()</code> multiple times to serve multiple directories. If a file cannot be found by one middleware function then it will simply be passed on to the subsequent middleware (the order that middleware is called is based on your declaration order).</p> + +<pre class="brush: js notranslate">app.use(express.static('public')) +app.use(express.static('media')) +</pre> + +<p>You can also create a virtual prefix for your static URLs, rather than having the files added to the base URL. For example, here we <a href="http://expressjs.com/en/4x/api.html#app.use">specify a mount path</a> so that the files are loaded with the prefix "/media":</p> + +<pre class="brush: js notranslate">app.use('/media', express.static('public')) +</pre> + +<p>Now, you can load the files that are in the <code>public</code> directory from the <code>/media</code> path prefix.</p> + +<pre class="notranslate"><code>http://localhost:3000/media/images/dog.jpg +http://localhost:3000/media/video/cat.mp4 +http://localhost:3000/media/cry.mp3</code> +</pre> + +<p>For more information, see <a href="Serving static files in Express">Serving static files in Express</a>.</p> + +<h3 id="핸들링_에러">핸들링 에러</h3> + +<p>Errors are handled by one or more special middleware functions that have four arguments, instead of the usual three: <code>(err, req, res, next)</code>. For example:</p> + +<pre class="brush: js notranslate">app.use(function (err, req, res, next) { + console.error(err.stack) + res.status(500).send('Something broke!') +}) +</pre> + +<p>These can return any content required, but must be called after all other <code>app.use()</code> and routes calls so that they are the last middleware in the request handling process!</p> + +<p>Express comes with a built-in error handler, which takes care of any remaining errors that might be encountered in the app. This default error-handling middleware function is added at the end of the middleware function stack. If you pass an error to <code>next()</code> and you do not handle it in an error handler, it will be handled by the built-in error handler; the error will be written to the client with the stack trace.</p> + +<div class="note"> +<p><strong>Note:</strong> The stack trace is not included in the production environment. To run it in production mode you need to set the the environment variable <code>NODE_ENV</code> to '<code>production'</code>.</p> +</div> + +<div class="note"> +<p><strong>Note:</strong> HTTP404 and other "error" status codes are not treated as errors. If you want to handle these, you can add a middleware function to do so. For more information see the <a href="http://expressjs.com/en/starter/faq.html#how-do-i-handle-404-responses">FAQ</a>.</p> +</div> + +<p>For more information see <a href="http://expressjs.com/en/guide/error-handling.html">Error handling</a> (Express docs).</p> + +<h3 id="데이터베이스의_사용">데이터베이스의 사용</h3> + +<p><em>Express</em> apps can use any database mechanism supported by <em>Node</em> (<em>Express</em> itself doesn't define any specific additional behaviour/requirements for database management). There are many options, including PostgreSQL, MySQL, Redis, SQLite, MongoDB, etc.</p> + +<p>In order to use these you have to first install the database driver using NPM. For example, to install the driver for the popular NoSQL MongoDB you would use the command:</p> + +<pre class="brush: bash notranslate"><code>$ npm install mongodb +</code></pre> + +<p>The database itself can be installed locally or on a cloud server. In your Express code you require the driver, connect to the database, and then perform create, read, update, and delete (CRUD) operations. The example below (from the Express documentation) shows how you can find "mammal" records using MongoDB.</p> + +<pre class="brush: js notranslate">var MongoClient = require('mongodb').MongoClient + +MongoClient.connect('mongodb://localhost:27017/animals', function (err, db) { + if (err) throw err + + db.collection('mammals').find().toArray(function (err, result) { + if (err) throw err + + console.log(result) + }) +})</pre> + +<p>Another popular approach is to access your database indirectly, via an Object Relational Mapper ("ORM"). In this approach you define your data as "objects" or "models" and the ORM maps these through to the underlying database format. This approach has the benefit that as a developer you can continue to think in terms of JavaScript objects rather than database semantics, and that there is an obvious place to perform validation and checking of incoming data. We'll talk more about databases in a later article.</p> + +<p>For more information see <a href="https://expressjs.com/en/guide/database-integration.html">Database integration</a> (Express docs).</p> + +<h3 id="데이터_랜더링시각화">데이터 랜더링(시각화)</h3> + +<p>Template engines (referred to as "view engines" by <em>Express</em>) allow you to specify the <em>structure</em> of an output document in a template, using placeholders for data that will be filled in when a page is generated. Templates are often used to create HTML, but can also create other types of document. Express has support for <a href="https://github.com/expressjs/express/wiki#template-engines">a number of template engines</a>, and there is a useful comparison of the more popular engines here: <a href="https://strongloop.com/strongblog/compare-javascript-templates-jade-mustache-dust/">Comparing JavaScript Templating Engines: Jade, Mustache, Dust and More</a>.</p> + +<p>In your application settings code you set the template engine to use and the location where Express should look for templates using the 'views' and 'view engines' settings, as shown below (you will also have to install the package containing your template library too!)</p> + +<pre class="brush: js notranslate">var express = require('express'); +var app = express(); + +// Set directory to contain the templates ('views') +app.set('views', path.join(__dirname, 'views')); + +// Set view engine to use, in this case 'some_template_engine_name' +app.set('view engine', 'some_template_engine_name'); +</pre> + +<p>The appearance of the template will depend on what engine you use. Assuming that you have a template file named "index.<template_extension>" that contains placeholders for data variables named 'title' and "message", you would call <code><a href="http://expressjs.com/en/4x/api.html#res.render">Response.render()</a></code> in a route handler function to create and send the HTML response:</p> + +<pre class="brush: js notranslate">app.get('/', function (req, res) { + res.render('index', { title: 'About dogs', message: 'Dogs rock!' }) +})</pre> + +<p>For more information see <a href="http://expressjs.com/en/guide/using-template-engines.html">Using template engines with Express</a> (Express docs).</p> + +<h3 id="파일구조">파일구조</h3> + +<p>Express makes no assumptions in terms of structure or what components you use. Routes, views, static files, and other application-specific logic can live in any number of files with any directory structure. While it is perfectly possible to have the whole <em>Express</em> application in one file, typically it makes sense to split your application into files based on function (e.g. account management, blogs, discussion boards) and architectural problem domain (e.g. model, view or controller if you happen to be using an <a href="/en-US/docs/Web/Apps/Fundamentals/Modern_web_app_architecture/MVC_architecture">MVC architecture</a>).</p> + +<p>In a later topic we'll use the <em>Express Application Generator</em>, which creates a modular app skeleton that we can easily extend for creating web applications.</p> + +<ul> +</ul> + +<h2 id="요약">요약</h2> + +<p id="Congratulations_you've_completed_the_first_step_in_your_ExpressNode_journey!_You_should_now_understand_Express_and_Node's_main_benefits_and_roughly_what_the_main_parts_of_an_Express_app_might_look_like_(routes_middleware_error_handling_and_template_code)._You_should_also_understand_that_with_Express_being_an_unopinionated_framework_the_way_you_pull_these_parts_together_and_the_libraries_that_you_use_are_largely_up_to_you!"><span style="color: #3b3c40; font-size: 14px; font-weight: normal; line-height: 1.5;">Congratulations, you've completed the first step in your Express/Node journey! You should now understand Express and Node's main benefits, and roughly what the main parts of an Express app might look like (routes, middleware, error handling, and template code). You should also understand that with Express being an unopinionated framework, the way you pull these parts together and the libraries that you use are largely up to you!</span></p> + +<p>Of course Express is deliberately a very lightweight web application framework, so much of its benefit and potential comes from third party libraries and features. We'll look at those in more detail in the following articles. In our next article we're going to look at setting up a Node development environment, so that you can start seeing some Express code in action.</p> + +<h2 id="더보기">더보기</h2> + +<ul> + <li><a href="https://nodejs.org/api/modules.html#modules_modules">Modules</a> (Node API docs)</li> + <li><a href="https://expressjs.com/">Express</a> (home page)</li> + <li><a href="http://expressjs.com/en/starter/basic-routing.html">Basic routing</a> (Express docs)</li> + <li><a href="http://expressjs.com/en/guide/routing.html">Routing guide</a> (Express docs)</li> + <li><a href="http://expressjs.com/en/guide/using-template-engines.html">Using template engines with Express</a> (Express docs)</li> + <li><a href="https://expressjs.com/en/guide/using-middleware.html">Using middleware</a> (Express docs)</li> + <li><a href="http://expressjs.com/en/guide/writing-middleware.html">Writing middleware for use in Express apps</a> (Express docs)</li> + <li><a href="https://expressjs.com/en/guide/database-integration.html">Database integration</a> (Express docs)</li> + <li><a href="Serving static files in Express">Serving static files in Express</a> (Express docs)</li> + <li><a href="http://expressjs.com/en/guide/error-handling.html">Error handling</a> (Express docs)</li> +</ul> + +<div>{{NextMenu("Learn/Server-side/Express_Nodejs/development_environment", "Learn/Server-side/Express_Nodejs")}}</div> diff --git a/files/ko/learn/server-side/express_nodejs/mongoose/index.html b/files/ko/learn/server-side/express_nodejs/mongoose/index.html new file mode 100644 index 0000000000..07c0f1e422 --- /dev/null +++ b/files/ko/learn/server-side/express_nodejs/mongoose/index.html @@ -0,0 +1,792 @@ +--- +title: 'Express Tutorial Part 3: Using a Database (with Mongoose)' +slug: Learn/Server-side/Express_Nodejs/mongoose +translation_of: Learn/Server-side/Express_Nodejs/mongoose +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/skeleton_website", "Learn/Server-side/Express_Nodejs/routes", "Learn/Server-side/Express_Nodejs")}}</div> + +<p class="summary">이번에는 데이터베이스를 간단히 소개하고, Node/Express 어플리케이션으로 데이터베이스를 어떻게 다루는 지 알아보겠습니다. 그리고 <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">LocalLibrary</a> 웹사이트를 위한 데이터베이스 접근을 제공하는 <a href="http://mongoosejs.com/">Mongoose</a>를 어떻게 사용할 수 있는지 보여줄 것입니다. 오브젝트 스키마와 모델을 선언하는 방법, 주요 필드 타입, 기본 유효성 검사를 설명합니다. 또한 당신이 모델 데이터에 접근할 수 있는 주요한 몇가지 방법들을 소개할 것입니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Prerequisites:</th> + <td><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website">Express Tutorial Part 2: Creating a skeleton website</a></td> + </tr> + <tr> + <th scope="row">Objective:</th> + <td>To be able to design and create your own models using Mongoose.</td> + </tr> + </tbody> +</table> + +<h2 id="개요">개요</h2> + +<p>도서관 직원들은 책과 대여자의 정보를 저장하기 위해 Local Library 웹사이트를 사용할 것입니다. 그리고 도서관 회원들은 책을 빌리고, 검색하며, 어떤 책이 이용한지 알아내고, 책 대여를 예약하거나 책을 빌릴 것입니다. 정보를 효과적으로 저장하고 가져오기 위해서, 우리는 그 정보를 데이터베이스에 저장할 것입니다.</p> + +<p>Express 앱은 다양한 데이터베이스를 사용할 수 있고, 당신에게 CRUD(<strong>C</strong>reate, <strong>R</strong>ead, <strong>U</strong>pdate and <strong>D</strong>elete)를 수행할 수 있는 여러 방법을 제공합니다. 이번 튜토리얼은 이용가능한 몇가지 선택지에 대한 간략한 개요를 제공하며, 더 나아가 우리가 선택한 몇가지 메커니즘에 대해선 자세히 알아볼 것입니다.</p> + +<h3 id="사용할_수_있는_데이터베이스는_무엇이_있나요">사용할 수 있는 데이터베이스는 무엇이 있나요?</h3> + +<p>Express 앱은 노드에서 지원하는 어떤 데이터베이스라도 사용가능합니다. (Express 자체는 데이터베이스 관리에 대한 특정한 추가 동작/요구사항을 정의하지 않습니다.) PostgreSQL, MySQL, Redis, SQLite, and MongoDB를 포함한 많은 <a href="https://expressjs.com/en/guide/database-integration.html">인기있는 데이터베이스 옵션</a>을 선택가능합니다.</p> + +<p>데이터베이스를 고를때, 당신은 생산성/러닝커브, 성능, 쉬운 리플리케이션/백업, 비용, 커뮤니티 지원 등을 고려해야 합니다. 하나의 "최고" 데이터베이스를 정하지 못하는 동안, 우리의 Local Library 같이 작은 규모에서 중간규모의 사이트에 적합한 거의 모든 어떤 솔루션이라도 사용 가능해야 합니다.</p> + +<p>옵션에 대한 더 많은 정보는 여기를 보십시오: <a href="https://expressjs.com/en/guide/database-integration.html">데이터베이스 인테그레이션</a> (Express 문서)</p> + +<h3 id="데이터베이스와_상호작용하는_최소의_방법은_무엇인가요">데이터베이스와 상호작용하는 최소의 방법은 무엇인가요?</h3> + +<p>데이터베이스와 상호작용하는 두가지 접근법이 있습니다: </p> + +<ul> + <li>데이터베이스의 네이티브 쿼리 언어를 사용 (예를 들어 SQL)</li> + <li>오브젝트 데이터 모델 ("ODM") / 오브젝트 관계형 모델 ("ORM")을 사용. ODM/ORM은 웹사이트의 데이터를 Javascript 오브젝트로 나타내며, 그다음 기본 데이터베이스에 매핑됩니다. 어떤 ORM은 특정 데이터베이스에 연결된 반면, 또다른 ORM은 데이터베이스와 무관한 백엔드를 제공합니다.</li> +</ul> + +<p>최상의 퍼포먼스는 SQL이나 데이터베이스에서 지원하는 쿼리 언어를 사용할때 얻을 수 있습니다. ODM은 오브젝트와 데이터베이스 포맷을 매핑하는 변환코드를 사용하기 때문에 종종 느리며, 가장 효율적인 데이터베이스 쿼리를 사용하지 않을 수 있습니다.</p> + +<p>ORM을 사용하는 이점은 프로그래머가 데이터베이스의 의미보다 JavaScript 객체로 계속해서 생각할 수 있다는 것입니다. - 이는 다른 데이터베이스(같거나 다른 웹사이트 어느 쪽에서든)들에서 작업해야 하는 경우 특히 그렇습니다. 또한 데이터의 유효성 및 확인을 확실히 할 수 있습니다.</p> + +<div class="note"> +<p><strong>팁:</strong> ODM/ORM을 사용하면 개발 및 유지 보수 비용이 절감됩니다. 네이티브 쿼리 언어에 친숙하거나 퍼포먼스가 중요한 것이 아니라면, ODM 사용을 적극 고려해야 합니다.</p> +</div> + +<p>NPM 패키지 매니저 사이트에는 사용가능한 많은 ODM/ORM 솔루션이 있습니다.(<a href="https://www.npmjs.com/browse/keyword/odm">odm</a> 과 <a href="https://www.npmjs.com/browse/keyword/orm">orm</a> 태그 집합을 확인하십시오.)</p> + +<p>이 글 작성 시점에 인기있었던 솔루션은 다음과 같습니다:</p> + +<ul> + <li><a href="https://www.npmjs.com/package/mongoose">Mongoose</a>: Mongoose는 비동기적인 환경에서 작업할 수 있도록 디자인된 <a href="https://www.mongodb.org/">MongoDB</a> 객체 모델링 툴입니다.</li> + <li><a href="https://www.npmjs.com/package/waterline">Waterline</a>: An ORM extracted from the Express-based <a href="http://sailsjs.com/">Sails</a> web framework. It provides a uniform API for accessing numerous different databases, including Redis, mySQL, LDAP, MongoDB, and Postgres.</li> + <li><a href="https://www.npmjs.com/package/bookshelf">Bookshelf</a>: Features both promise-based and traditional callback interfaces, providing transaction support, eager/nested-eager relation loading, polymorphic associations, and support for one-to-one, one-to-many, and many-to-many relations. Works with PostgreSQL, MySQL, and SQLite3.</li> + <li><a href="https://www.npmjs.com/package/objection">Objection</a>: Makes it as easy as possible to use the full power of SQL and the underlying database engine (supports SQLite3, Postgres, and MySQL).</li> + <li> + <p><a href="https://www.npmjs.com/package/sequelize">Sequelize</a> is a promise-based ORM for Node.js and io.js. It supports the dialects PostgreSQL, MySQL, MariaDB, SQLite and MSSQL and features solid transaction support, relations, read replication and more.</p> + </li> +</ul> + +<p>일반적으로 솔루션을 선택할 때, 당신은 제공되는 기능과 "커뮤니티 활동" (다운로드, 공헌도, 버그 리포트, 문서 퀄리티 등) 모두를 고려해야 합니다. 이에 대한 글을 작성하고 있는 시점에, 몽구스는 가장 유명한 ORM이며, 당신이 MongoDB를 사용한다면 몽구스는 합리적인 선택입니다.</p> + +<h3 id="Using_Mongoose_and_MongoDb_for_the_LocalLibrary">Using Mongoose and MongoDb for the LocalLibrary</h3> + +<p>For the <em>Local Library</em> example (and the rest of this topic) we're going to use the <a href="https://www.npmjs.com/package/mongoose">Mongoose ODM</a> to access our library data. Mongoose acts as a front end to <a href="https://www.mongodb.com/what-is-mongodb">MongoDB</a>, an open source <a href="https://en.wikipedia.org/wiki/NoSQL">NoSQL</a> database that uses a document-oriented data model. A “collection” of “documents”, in a MongoDB database, <a href="https://docs.mongodb.com/manual/core/databases-and-collections/#collections">is analogous to</a> a “table” of “rows” in a relational database.</p> + +<p>This ODM and database combination is extremely popular in the Node community, partially because the document storage and query system looks very much like JSON, and is hence familiar to JavaScript developers.</p> + +<div class="note"> +<p><strong>Tip:</strong> You don't need to know MongoDB in order to use Mongoose, although parts of the <a href="http://mongoosejs.com/docs/guide.html">Mongoose documentation</a> <em>are</em> easier to use and understand if you are already familiar with MongoDB.</p> +</div> + +<p>The rest of this tutorial shows how to define and access the Mongoose schema and models for the <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">LocalLibrary website</a> example.</p> + +<h2 id="Designing_the_LocalLibrary_models">Designing the LocalLibrary models</h2> + +<p>Before you jump in and start coding the models, it's worth taking a few minutes to think about what data we need to store and the relationships between the different objects.</p> + +<p>We know that we need to store information about books (title, summary, author, genre, ISBN) and that we might have multiple copies available (with globally unique ids, availability statuses, etc.). We might need to store more information about the author than just their name, and there might be multiple authors with the same or similar names. We want to be able to sort information based on book title, author, genre, and category.</p> + +<p>When designing your models it makes sense to have separate models for every "object" (group of related information). In this case the obvious objects are books, book instances, and authors.</p> + +<p>You might also want to use models to represent selection-list options (e.g. like a drop down list of choices), rather than hard coding the choices into the website itself — this is recommended when all the options aren't known up front or may change. The obvious candidate for a model of this type is the book genre (e.g. Science Fiction, French Poetry, etc.)</p> + +<p>Once we've decided on our models and fields, we need to think about the relationships between them.</p> + +<p>With that in mind, the UML association diagram below shows the models we'll define in this case (as boxes). As discussed above, we've created models for book (the generic details of the book), book instance (status of specific physical copies of the book available in the system), and author. We have also decided to have a model for genre, so that values can be created dynamically. We've decided not to have a model for the <code>BookInstance:status</code> — we will hard code the acceptable values because we don't expect these to change. Within each of the boxes you can see the model name, the field names and types, and also the methods and their return types.</p> + +<p>The diagram also shows the relationships between the models, including their <em>multiplicities</em>. The multiplicities are the numbers on the diagram showing the numbers (maximum and minimum) of each model that may be present in the relationship. For example, the connecting line between the boxes shows that <code>Book</code> and a <code>Genre</code> are related. The numbers close to the <code>Book</code> model show that a book must have zero or more <code>Genre</code> (as many as you like), while the numbers on the other end of the line next to the <code>Genre</code> show that it can have zero or more associated books.</p> + +<div class="note"> +<p><strong>Note</strong>: As discussed in our <a href="#related_documents">Mongoose primer</a> below it is often better to have the field that defines the relationship between the documents/models in just <em>one</em> model (you can still find the reverse relationship by searching for the associated <code>_id</code> in the other model). Below we have chosen to define the relationship between Book/Genre and Book/Author in the Book schema, and the relationship between the Book/BookInstance in the BookInstance Schema. This choice was somewhat arbitrary — we could equally well have had the field in the other schema.</p> +</div> + +<p><img alt="Mongoose Library Model with correct cardinality" src="https://mdn.mozillademos.org/files/15645/Library%20Website%20-%20Mongoose_Express.png" style="height: 620px; width: 737px;"></p> + +<div class="note"> +<p><strong>Note</strong>: The next section provides a basic primer explaining how models are defined and used. As you read it, consider how we will construct each of the models in the diagram above.</p> +</div> + +<h2 id="Mongoose_primer">Mongoose primer</h2> + +<p>This section provides an overview of how to connect Mongoose to a MongoDB database, how to define a schema and a model, and how to make basic queries. </p> + +<div class="note"> +<p><strong>Note:</strong> This primer is "heavily influenced" by the <a href="https://www.npmjs.com/package/mongoose">Mongoose quick start</a> on <em>npm</em> and the <a href="http://mongoosejs.com/docs/guide.html">official documentation</a>.</p> +</div> + +<h3 id="Installing_Mongoose_and_MongoDB">Installing Mongoose and MongoDB</h3> + +<p>Mongoose is installed in your project (<strong>package.json</strong>) like any other dependency — using NPM. To install it, use the following command inside your project folder:</p> + +<pre class="brush: bash"><code>npm install mongoose</code> +</pre> + +<p>Installing <em>Mongoose</em> adds all its dependencies, including the MongoDB database driver, but it does not install MongoDB itself. If you want to install a MongoDB server then you can <a href="https://www.mongodb.com/download-center">download installers from here</a> for various operating systems and install it locally. You can also use cloud-based MongoDB instances.</p> + +<div class="note"> +<p><strong>Note:</strong> For this tutorial we'll be using the mLab cloud-based <em>database as a service</em> <a href="https://mlab.com/plans/pricing/">sandbox tier</a> to provide the database. This is suitable for development, and makes sense for the tutorial because it makes "installation" operating system independent (database-as-a-service is also one approach you might well use for your production database).</p> +</div> + +<h3 id="Connecting_to_MongoDB">Connecting to MongoDB</h3> + +<p><em>Mongoose</em> requires a connection to a MongoDB database. You can <code>require()</code> and connect to a locally hosted database with <code>mongoose.connect()</code>, as shown below.</p> + +<pre class="brush: js">//Import the mongoose module +var mongoose = require('mongoose'); + +//Set up default mongoose connection +var mongoDB = 'mongodb://127.0.0.1/my_database'; +mongoose.connect(mongoDB); +// Get Mongoose to use the global promise library +mongoose.Promise = global.Promise; +//Get the default connection +var db = mongoose.connection; + +//Bind connection to error event (to get notification of connection errors) +db.on('error', console.error.bind(console, 'MongoDB connection error:'));</pre> + +<p>You can get the default <code>Connection</code> object with <code>mongoose.connection</code>. Once connected, the open event is fired on the <code>Connection</code> instance.</p> + +<div class="note"> +<p><strong>Tip:</strong> If you need to create additional connections you can use <code>mongoose.createConnection()</code>. This takes the same form of database URI (with host, database, port, options etc.) as <code>connect()</code> and returns a <code>Connection</code> object).</p> +</div> + +<h3 id="Defining_and_creating_models">Defining and creating models</h3> + +<p>Models are <em>defined </em>using the <code>Schema</code> interface. The Schema allows you to define the fields stored in each document along with their validation requirements and default values. In addition, you can define static and instance helper methods to make it easier to work with your data types, and also virtual properties that you can use like any other field, but which aren't actually stored in the database (we'll discuss a bit further below).</p> + +<p>Schemas are then "compiled" into models using the <code>mongoose.model()</code> method. Once you have a model you can use it to find, create, update, and delete objects of the given type.</p> + +<div class="note"> +<p><strong>Note:</strong> Each model maps to a <em>collection</em> of <em>documents</em> in the MongoDB database. The documents will contain the fields/schema types defined in the model <code>Schema</code>.</p> +</div> + +<h4 id="Defining_schemas">Defining schemas</h4> + +<p>The code fragment below shows how you might define a simple schema. First you <code>require()</code> mongoose, then use the Schema constructor to create a new schema instance, defining the various fields inside it in the constructor's object parameter.</p> + +<pre class="brush: js">//Require Mongoose +var mongoose = require('mongoose'); + +//Define a schema +var Schema = mongoose.Schema; + +var SomeModelSchema = new Schema({ + a_string: String, + a_date: Date +}); +</pre> + +<p>In the case above we just have two fields, a string and a date. In the next sections we will show some of the other field types, validation, and other methods.</p> + +<h4 id="Creating_a_model">Creating a model</h4> + +<p>Models are created from schemas using the <code>mongoose.model()</code> method:</p> + +<pre class="brush: js">// Define schema +var Schema = mongoose.Schema; + +var SomeModelSchema = new Schema({ + a_string: String, + a_date: Date +}); + +<strong>// Compile model from schema +var SomeModel = mongoose.model('SomeModel', SomeModelSchema );</strong></pre> + +<p>The first argument is the singular name of the collection that will be created for your model (Mongoose will create the database collection for the above model <em>SomeModel</em> above), and the second argument is the schema you want to use in creating the model.</p> + +<div class="note"> +<p><strong>Note:</strong> Once you've defined your model classes you can use them to create, update, or delete records, and to run queries to get all records or particular subsets of records. We'll show you how to do this in the <a href="#Using_models">Using models</a> section, and when we create our views.</p> +</div> + +<h4 id="스키마_타입_(필드)">스키마 타입 (필드)</h4> + +<p>한 스키마는 임의의 숫자의 필드들을 가질 수 있습니다.(각각의 필드는 MongoDB에 저장된 문서의 필드를 대표합니다.) 아래의 예제 스키마는 일반적인 필드 타입들을 보여주고 있으며 그들이 어떻게 선언되는지 나타냅니다.</p> + +<pre class="brush: js">var schema = new Schema( +{ + name: <strong>String</strong>, + binary: <strong>Buffer</strong>, + living: <strong>Boolean</strong>, + updated: { type: <strong>Date</strong>, default: Date.now }, + age: { type: <strong>Number</strong>, min: 18, max: 65, required: true }, + mixed: <strong>Schema.Types.Mixed</strong>, + _someId: <strong>Schema.Types.ObjectId</strong>, + array: <strong>[]</strong>, + ofString: [<strong>String</strong>], // You can also have an array of each of the other types too. + nested: { stuff: { type: <strong>String</strong>, lowercase: true, trim: true } } +})</pre> + +<p>Most of the <a href="http://mongoosejs.com/docs/schematypes.html">SchemaTypes</a> (the descriptors after “type:” or after field names) are self explanatory. The exceptions are:</p> + +<ul> + <li><code>ObjectId</code>: Represents specific instances of a model in the database. For example, a book might use this to represent its author object. This will actually contain the unique ID (<code>_id</code>) for the specified object. We can use the <code>populate()</code> method to pull in the associated information when needed.</li> + <li><a href="http://mongoosejs.com/docs/schematypes.html#mixed">Mixed</a>: 임의의 스키마 타입입니다.(어떤 타입도 될 수 있음)</li> + <li><font face="Consolas, Liberation Mono, Courier, monospace">[]</font>: An array of items. You can perform JavaScript array operations on these models (push, pop, unshift, etc.). The examples above show an array of objects without a specified type and an array of <code>String</code> objects, but you can have an array of any type of object.</li> +</ul> + +<p>The code also shows both ways of declaring a field:</p> + +<ul> + <li>Field <em>name</em> and <em>type</em> as a key-value pair (i.e. as done with fields <code>name</code>, <code>binary </code>and <code>living</code>).</li> + <li>Field <em>name</em> followed by an object defining the <code>type</code>, and any other <em>options</em> for the field. Options include things like: + <ul> + <li>default values.</li> + <li>built-in validators (e.g. max/min values) and custom validation functions.</li> + <li>Whether the field is required</li> + <li>Whether <code>String</code> fields should automatically be set to lowercase, uppercase, or trimmed (e.g. <code>{ type: <strong>String</strong>, lowercase: true, trim: true }</code>)</li> + </ul> + </li> +</ul> + +<p>For more information about options see <a href="http://mongoosejs.com/docs/schematypes.html">SchemaTypes</a> (Mongoose docs).</p> + +<h4 id="Validation">Validation</h4> + +<p>Mongoose provides built-in and custom validators, and synchronous and asynchronous validators. It allows you to specify both the acceptable range or values and the error message for validation failure in all cases.</p> + +<p>The built-in validators include:</p> + +<ul> + <li>All <a href="http://mongoosejs.com/docs/schematypes.html">SchemaTypes</a> have the built-in <a href="http://mongoosejs.com/docs/api.html#schematype_SchemaType-required">required</a> validator. This is used to specify whether the field must be supplied in order to save a document.</li> + <li><a href="http://mongoosejs.com/docs/api.html#schema-number-js">Numbers</a> have <a href="http://mongoosejs.com/docs/api.html#schema_number_SchemaNumber-min">min</a> and <a href="http://mongoosejs.com/docs/api.html#schema_number_SchemaNumber-max">max</a> validators.</li> + <li><a href="http://mongoosejs.com/docs/api.html#schema-string-js">Strings</a> have: + <ul> + <li><a href="http://mongoosejs.com/docs/api.html#schema_string_SchemaString-enum">enum</a>: specifies the set of allowed values for the field.</li> + <li><a href="http://mongoosejs.com/docs/api.html#schema_string_SchemaString-match">match</a>: specifies a regular expression that the string must match.</li> + <li><a href="http://mongoosejs.com/docs/api.html#schema_string_SchemaString-maxlength">maxlength</a> and <a href="http://mongoosejs.com/docs/api.html#schema_string_SchemaString-minlength">minlength</a> for the string.</li> + </ul> + </li> +</ul> + +<p>The example below (slightly modified from the Mongoose documents) shows how you can specify some of the validator types and error messages:</p> + +<pre class="brush: js"><code> + var breakfastSchema = new Schema({ + eggs: { + type: Number, + min: [6, 'Too few eggs'], + max: 12 + required: [true, 'Why no eggs?'] + }, + drink: { + type: String, + enum: ['Coffee', 'Tea', 'Water',] + } + }); +</code></pre> + +<p>For complete information on field validation see <a href="http://mongoosejs.com/docs/validation.html">Validation</a> (Mongoose docs).</p> + +<h4 id="Virtual_properties">Virtual properties</h4> + +<p>Virtual properties are document properties that you can get and set but that do not get persisted to MongoDB. The getters are useful for formatting or combining fields, while setters are useful for de-composing a single value into multiple values for storage. The example in the documentation constructs (and deconstructs) a full name virtual property from a first and last name field, which is easier and cleaner than constructing a full name every time one is used in a template.</p> + +<div class="note"> +<p><strong>Note:</strong> We will use a virtual property in the library to define a unique URL for each model record using a path and the record's <code>_id</code> value.</p> +</div> + +<p>For more information see <a href="http://mongoosejs.com/docs/guide.html#virtuals">Virtuals</a> (Mongoose documentation).</p> + +<h4 id="Methods_and_query_helpers">Methods and query helpers</h4> + +<p>A schema can also have <a href="http://mongoosejs.com/docs/guide.html#methods">instance methods</a>, <a href="http://mongoosejs.com/docs/guide.html#statics">static methods</a>, and <a href="http://mongoosejs.com/docs/guide.html#query-helpers">query helpers</a>. The instance and static methods are similar, but with the obvious difference that an instance method is associated with a particular record and has access to the current object. Query helpers allow you to extend mongoose's <a href="http://mongoosejs.com/docs/queries.html">chainable query builder API</a> (for example, allowing you to add a query "byName" in addition to the <code>find()</code>, <code>findOne()</code> and <code>findById()</code> methods).</p> + +<h3 id="Using_models">Using models</h3> + +<p>Once you've created a schema you can use it to create models. The model represents a collection of documents in the database that you can search, while the model's instances represent individual documents that you can save and retrieve.</p> + +<p>We provide a brief overview below. For more information see: <a href="http://mongoosejs.com/docs/models.html">Models</a> (Mongoose docs).</p> + +<h4 id="Creating_and_modifying_documents">Creating and modifying documents</h4> + +<p>To create a record you can define an instance of the model and then call <code>save()</code>. The examples below assume SomeModel is a model (with a single field "name") that we have created from our schema.</p> + +<pre class="brush: js"><code>// Create an instance of model SomeModel +var awesome_instance = new </code>SomeModel<code>({ name: 'awesome' }); + +// Save the new model instance, passing a callback +awesome_instance.save(function (err) { + if (err) return handleError(err); + // saved! +}); +</code></pre> + +<p>Creation of records (along with updates, deletes, and queries) are asynchronous operations — you supply a callback that is called when the operation completes. The API uses the error-first argument convention, so the first argument for the callback will always be an error value (or null). If the API returns some result, this will be provided as the second argument.</p> + +<p>You can also use <code>create()</code> to define the model instance at the same time as you save it. The callback will return an error for the first argument and the newly-created model instance for the second argument.</p> + +<pre class="brush: js">SomeModel<code>.create({ name: 'also_awesome' }, function (err, awesome_instance) { + if (err) return handleError(err); + // saved! +});</code></pre> + +<p>Every model has an associated connection (this will be the default connection when you use <code>mongoose.model()</code>). You create a new connection and call <code>.model()</code> on it to create the documents on a different database.</p> + +<p>You can access the fields in this new record using the dot syntax, and change the values. You have to call <code>save()</code> or <code>update()</code> to store modified values back to the database.</p> + +<pre class="brush: js">// Access model field values using dot notation +console.log(<code>awesome_instance.name</code>); //should log '<code>also_awesome</code>' + +// Change record by modifying the fields, then calling save(). +<code>awesome_instance</code>.name="New cool name"; +<code>awesome_instance.save(function (err) { + if (err) return handleError(err); // saved! + });</code> +</pre> + +<h4 id="Searching_for_records">Searching for records</h4> + +<p>You can search for records using query methods, specifying the query conditions as a JSON document. The code fragment below shows how you might find all athletes in a database that play tennis, returning just the fields for athlete <em>name</em> and <em>age</em>. Here we just specify one matching field (sport) but you can add more criteria, specify regular expression criteria, or remove the conditions altogether to return all athletes.</p> + +<pre class="brush: js"><code>var Athlete = mongoose.model('Athlete', yourSchema); + +// find all athletes who play tennis, selecting the 'name' and 'age' fields +Athlete.find({ 'sport': 'Tennis' }, 'name age', function (err, athletes) { + if (err) return handleError(err); + // 'athletes' contains the list of athletes that match the criteria. +})</code></pre> + +<p>If you specify a callback, as shown above, the query will execute immediately. The callback will be invoked when the search completes.</p> + +<div class="note"> +<p><strong>Note:</strong> All callbacks in Mongoose use the pattern <code>callback(error, result)</code>. If an error occurs executing the query, the <code>error</code> parameter will contain an error document, and <code>result</code> will be null. If the query is successful, the <code>error</code> parameter will be null, and the <code>result</code> will be populated with the results of the query.</p> +</div> + +<p>If you don't specify a callback then the API will return a variable of type <a href="http://mongoosejs.com/docs/api.html#query-js">Query</a>. You can use this query object to build up your query and then execute it (with a callback) later using the <code>exec()</code> method.</p> + +<pre class="brush: js"><code>// find all athletes that play tennis +var query = Athlete.find({ 'sport': 'Tennis' }); + +// selecting the 'name' and 'age' fields +query.select('name age'); + +// limit our results to 5 items +query.limit(5); + +// sort by age +query.sort({ age: -1 }); + +// execute the query at a later time +query.exec(function (err, athletes) { + if (err) return handleError(err); + // athletes contains an ordered list of 5 athletes who play Tennis +})</code></pre> + +<p>Above we've defined the query conditions in the <code>find()</code> method. We can also do this using a <code>where()</code> function, and we can chain all the parts of our query together using the dot operator (.) rather than adding them separately. The code fragment below is the same as our query above, with an additional condition for the age.</p> + +<pre><code>Athlete. + find(). + where('sport').equals('Tennis'). + where('age').gt(17).lt(50). //Additional where query + limit(5). + sort({ age: -1 }). + select('name age'). + exec(callback); // where callback is the name of our callback function.</code></pre> + +<p>The <a href="http://mongoosejs.com/docs/api.html#query_Query-find">find()</a> method gets all matching records, but often you just want to get one match. The following methods query for a single record:</p> + +<ul> + <li><code><a href="http://mongoosejs.com/docs/api.html#model_Model.findById">findById()</a></code>: Finds the document with the specified <code>id</code> (every document has a unique <code>id</code>).</li> + <li><code><a href="http://mongoosejs.com/docs/api.html#query_Query-findOne">findOne()</a></code>: Finds a single document that matches the specified criteria.</li> + <li><code><a href="http://mongoosejs.com/docs/api.html#model_Model.findByIdAndRemove">findByIdAndRemove()</a></code>, <code><a href="http://mongoosejs.com/docs/api.html#model_Model.findByIdAndUpdate">findByIdAndUpdate()</a></code>, <code><a href="http://mongoosejs.com/docs/api.html#query_Query-findOneAndRemove">findOneAndRemove()</a></code>, <code><a href="http://mongoosejs.com/docs/api.html#query_Query-findOneAndUpdate">findOneAndUpdate()</a></code>: Finds a single document by <code>id</code> or criteria and either update or remove it. These are useful convenience functions for updating and removing records.</li> +</ul> + +<div class="note"> +<p><strong>Note:</strong> There is also a <code><a href="http://mongoosejs.com/docs/api.html#model_Model.count">count()</a></code> method that you can use to get the number of items that match conditions. This is useful if you want to perform a count without actually fetching the records.</p> +</div> + +<p>There is a lot more you can do with queries. For more information see: <a href="http://mongoosejs.com/docs/queries.html">Queries</a> (Mongoose docs).</p> + +<h4 id="Working_with_related_documents_—_population">Working with related documents — population</h4> + +<p>You can create references from one document/model instance to another using the <code>ObjectId</code> schema field, or from one document to many using an array of <code>ObjectIds</code>. The field stores the id of the related model. If you need the actual content of the associated document, you can use the <code><a href="http://mongoosejs.com/docs/api.html#query_Query-populate">populate()</a></code> method in a query to replace the id with the actual data.</p> + +<p>For example, the following schema defines authors and stories. Each author can have multiple stories, which we represent as an array of <code>ObjectId</code>. Each story can have a single author. The "ref" (highlighted in bold below) tells the schema which model can be assigned to this field.</p> + +<pre class="brush: js"><code>var mongoose = require('mongoose') + , Schema = mongoose.Schema + +var authorSchema = Schema({ + name : String, + stories : [{ type: Schema.Types.ObjectId, <strong>ref</strong>: 'Story' }] +}); + +var storySchema = Schema({ + author : { type: Schema.Types.ObjectId, <strong>ref</strong>: 'Author' }, + title : String +}); + +var Story = mongoose.model('Story', storySchema); +var Author = mongoose.model('Author', authorSchema);</code></pre> + +<p>We can save our references to the related document by assigning the <code>_id</code> value. Below we create an author, then a book, and assign the author id to our stories author field.</p> + +<pre class="brush: js"><code>var bob = new Author({ name: 'Bob Smith' }); + +bob.save(function (err) { + if (err) return handleError(err); + + //Bob now exists, so lets create a story + var story = new Story({ + title: "Bob goes sledding", + author: bob._id // assign the _id from the our author Bob. This ID is created by default! + }); + + story.save(function (err) { + if (err) return handleError(err); + // Bob now has his story + }); +});</code></pre> + +<p>Our story document now has an author referenced by the author document's ID. In order to get the author information in our story results we use <code>populate()</code>, as shown below.</p> + +<pre class="brush: js"><code>Story +.findOne({ title: 'Bob goes sledding' }) +.populate('author') //This populates the author id with actual author information! +.exec(function (err, story) { + if (err) return handleError(err); + console.log('The author is %s', story.author.name); + // prints "The author is Bob Smith" +});</code></pre> + +<div class="note"> +<p><strong>Note:</strong> Astute readers will have noted that we added an author to our story, but we didn't do anything to add our story to our author's <code>stories</code> array. How then can we get all stories by a particular author? One way would be to add our author to the stories array, but this would result in us having two places where the information relating authors and stories needs to be maintained.</p> + +<p>A better way is to get the <code>_id</code> of our <em>author</em>, then use <code>find()</code> to search for this in the author field across all stories.</p> + +<pre class="brush: js"><code>Story +.find({ author : bob._id }) +.exec(function (err, stories) { + if (err) return handleError(err); + // returns all stories that have Bob's id as their author. +});</code> +</pre> +</div> + +<p>This is almost everything you need to know about working with related items<em> for this tutorial</em>. For more detailed information see <a href="http://mongoosejs.com/docs/populate.html">Population</a> (Mongoose docs).</p> + +<h3 id="One_schemamodel_per_file">One schema/model per file</h3> + +<p>While you can create schemas and models using any file structure you like, we highly recommend defining each model schema in its own module (file), exporting the method to create the model. This is shown below:</p> + +<pre class="brush: js"><code>// File: ./models/somemodel.js + +//Require Mongoose +var mongoose = require('mongoose'); + +//Define a schema +var Schema = mongoose.Schema; + +var SomeModelSchema = new Schema({ + a_string : String, + a_date : Date, +}); + +<strong>//Export function to create "SomeModel" model class +module.exports = mongoose.model('SomeModel', SomeModelSchema );</strong></code></pre> + +<p>You can then require and use the model immediately in other files. Below we show how you might use it to get all instances of the model.</p> + +<pre class="brush: js"><code>//Create a SomeModel model just by requiring the module +var SomeModel = require('../models/somemodel') + +// Use the SomeModel object (model) to find all SomeModel records +SomeModel.find(callback_function);</code></pre> + +<h2 id="Setting_up_the_MongoDB_database">Setting up the MongoDB database</h2> + +<p>Now that we understand something of what Mongoose can do and how we want to design our models, it's time to start work on the <em>LocalLibrary</em> website. The very first thing we want to do is set up a MongoDb database that we can use to store our library data.</p> + +<p>For this tutorial we're going to use <a href="https://mlab.com/welcome/">mLab</a>'s free cloud-hosted "<a href="https://mlab.com/plans/pricing/">sandbox</a>" database. This database tier is not considered suitable for production websites because it has no redundancy, but it is great for development and prototyping. We're using it here because it is free and easy to set up, and because mLab is a popular <em>database as a service</em> vendor that you might reasonably choose for your production database (other popular choices at the time of writing include <a href="https://www.compose.com/">Compose</a>, <a href="https://scalegrid.io/pricing.html">ScaleGrid</a> and <a href="https://www.mongodb.com/cloud/atlas">MongoDB Atlas</a>).</p> + +<div class="note"> +<p><strong>Note:</strong> If you prefer you can set up a MongoDb database locally by downloading and installing the <a href="https://www.mongodb.com/download-center">appropriate binaries for your system</a>. The rest of the instructions in this article would be similar, except for the database URL you would specify when connecting.</p> +</div> + +<p>You will first need to <a href="https://mlab.com/signup/">create an account</a> with mLab (this is free, and just requires that you enter basic contact details and acknowledge their terms of service). </p> + +<p>After logging in, you'll be taken to the <a href="https://mlab.com/home">home</a> screen:</p> + +<ol> + <li>Click <strong>Create New</strong> in the <em>MongoDB Deployments</em> section.<img alt="" src="https://mdn.mozillademos.org/files/14446/mLabCreateNewDeployment.png" style="height: 415px; width: 1000px;"></li> + <li>This will open the <em>Cloud Provider Selection </em>screen.<br> + <img alt="MLab - screen for new deployment" src="https://mdn.mozillademos.org/files/15661/mLab_new_deployment_form_v2.png" style="height: 931px; width: 1297px;"><br> + + <ul> + <li>Select the SANDBOX (Free) plan from the Plan Type section. </li> + <li>Select any provider from the <em>Cloud Provider </em>section. Different providers offer different regions (displayed below the selected plan type).</li> + <li>Click the <strong>Continue</strong> button.</li> + </ul> + </li> + <li>This will open the <em>Select Region</em> screen. + <p><img alt="Select new region screen" src="https://mdn.mozillademos.org/files/15662/mLab_new_deployment_select_region_v2.png" style="height: 570px; width: 1293px;"></p> + + <ul> + <li> + <p>Select the region closest to you and then <strong>Continue</strong>.</p> + </li> + </ul> + </li> + <li> + <p>This will open the <em>Final Details</em> screen.<br> + <img alt="New deployment database name" src="https://mdn.mozillademos.org/files/15663/mLab_new_deployment_final_details.png" style="height: 569px; width: 1293px;"></p> + + <ul> + <li> + <p>Enter the name for the new database as <code>local_library</code> and then select <strong>Continue</strong>.</p> + </li> + </ul> + </li> + <li> + <p>This will open the <em>Order Confirmation</em> screen.<br> + <img alt="Order confirmation screen" src="https://mdn.mozillademos.org/files/15664/mLab_new_deployment_order_confirmation.png" style="height: 687px; width: 1290px;"></p> + + <ul> + <li> + <p>Click <strong>Submit Order</strong> to create the database.</p> + </li> + </ul> + </li> + <li> + <p>You will be returned to the home screen. Click on the new database you just created to open its details screen. As you can see the database has no collections (data).<br> + <img alt="mLab - Database details screen" src="https://mdn.mozillademos.org/files/15665/mLab_new_deployment_database_details.png" style="height: 700px; width: 1398px;"><br> + <br> + The URL that you need to use to access your database is displayed on the form above (shown for this database circled above). In order to use this you need to create a database user that you can specify in the URL.</p> + </li> + <li>Click the <strong>Users</strong> tab and select the <strong>Add database user</strong> button.</li> + <li>Enter a username and password (twice), and then press <strong>Create</strong>. Do not select <em>Make read only</em>.<br> + <img alt="" src="https://mdn.mozillademos.org/files/14454/mLab_database_users.png" style="height: 204px; width: 600px;"></li> +</ol> + +<p>You now have now created the database, and have an URL (with username and password) that can be used to access it. This will look something like: <code>mongodb://your_user_namer:your_password@ds119748.mlab.com:19748/local_library</code>.</p> + +<h2 id="Install_Mongoose">Install Mongoose</h2> + +<p>Open a command prompt and navigate to the directory where you created your <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website">skeleton Local Library website</a>. Enter the following command to install Mongoose (and its dependencies) and add it to your <strong>package.json</strong> file, unless you have already done so when reading the <a href="#Installing_Mongoose_and_MongoDB">Mongoose Primer</a> above.</p> + +<pre class="brush: bash">npm install mongoose --save +</pre> + +<h2 id="Connect_to_MongoDB">Connect to MongoDB</h2> + +<p>Open <strong>/app.js</strong> (in the root of your project) and copy the following text below where you declare the <em>Express application object</em> (after the line <code>var app = express();</code>). Replace the database url string ('<em>insert_your_database_url_here</em>') with the location URL representing your own database (i.e. using the information from <a href="#Setting_up_the_MongoDB_database">from mLab</a>).</p> + +<pre class="brush: js">//Set up mongoose connection +var mongoose = require('mongoose'); +var mongoDB = '<em>insert_your_database_url_here</em>'; +mongoose.connect(mongoDB); +mongoose.Promise = global.Promise; +var db = mongoose.connection; +db.on('error', console.error.bind(console, 'MongoDB connection error:'));</pre> + +<p>As discussed <a href="#Connecting_to_MongoDB">in the Mongoose primer above</a>, this code creates the default connection to the database and binds to the error event (so that errors will be printed to the console). </p> + +<h2 id="Defining_the_LocalLibrary_Schema">Defining the LocalLibrary Schema</h2> + +<p>We will define a separate module for each model, as <a href="#One_schemamodel_per_file">discussed above</a>. Start by creating a folder for our models in the project root (<strong>/models</strong>) and then create separate files for each of the models:</p> + +<pre>/express-locallibrary-tutorial //the project root + <strong>/models</strong> + <strong>author.js</strong> + <strong>book.js</strong> + <strong>bookinstance.js</strong> + <strong>genre.js</strong> +</pre> + +<h3 id="Author_model">Author model</h3> + +<p>Copy the <code>Author</code> schema code shown below and paste it into your <strong>./models/author.js</strong> file. The scheme defines an author has having <code>String</code> SchemaTypes for the first and family names, that are required and have a maximum of 100 characters, and <code>Date</code> fields for the date of birth and death.</p> + +<pre class="brush: js">var mongoose = require('mongoose'); + +var Schema = mongoose.Schema; + +var AuthorSchema = new Schema( + { + first_name: {type: String, required: true, max: 100}, + family_name: {type: String, required: true, max: 100}, + date_of_birth: {type: Date}, + date_of_death: {type: Date}, + } +); + +<strong>// Virtual for author's full name +AuthorSchema +.virtual('name') +.get(function () { + return this.family_name + ', ' + this.first_name; +});</strong> + +// Virtual for author's URL +AuthorSchema +.virtual('url') +.get(function () { + return '/catalog/author/' + this._id; +}); + +//Export model +module.exports = mongoose.model('Author', AuthorSchema); + +</pre> + +<p>We've also declared a <a href="#Virtual_properties">virtual</a> for the AuthorSchema named "url" that returns the absolute URL required to get a particular instance of the model — we'll use the property in our templates whenever we need to get a link to a particular author.</p> + +<div class="note"> +<p><strong>Note:</strong> Declaring our URLs as a virtual in the schema is a good idea because then the URL for an item only ever needs to be changed in one place.<br> + At this point a link using this URL wouldn't work, because we haven't got any routes handling code for individual model instances. We'll set those up in a later article!</p> +</div> + +<p>At the end of the module we export the model.</p> + +<h3 id="Book_model">Book model</h3> + +<p>Copy the <code>Book</code> schema code shown below and paste it into your <strong>./models/book.js</strong> file. Most of this is similar to the author model — we've declared a schema with a number of string fields and a virtual for getting the URL of specific book records, and we've exported the model.</p> + +<pre class="brush: js">var mongoose = require('mongoose'); + +var Schema = mongoose.Schema; + +var BookSchema = new Schema( + { + title: {type: String, required: true}, + <strong> author: {type: Schema.ObjectId, ref: 'Author', required: true},</strong> + summary: {type: String, required: true}, + isbn: {type: String, required: true}, + <strong> genre: [{type: Schema.ObjectId, ref: 'Genre'}]</strong> + } +); + +// Virtual for book's URL +BookSchema +.virtual('url') +.get(function () { + return '/catalog/book/' + this._id; +}); + +//Export model +module.exports = mongoose.model('Book', BookSchema); +</pre> + +<p>The main difference here is that we've created two references to other models:</p> + +<ul> + <li>author is a reference to a single <code>Author</code> model object, and is required.</li> + <li>genre is a reference to an array of <code>Genre</code> model objects. We haven't declared this object yet!</li> +</ul> + +<h3 id="BookInstance_model">BookInstance model</h3> + +<p>Finally, copy the <code>BookInstance</code> schema code shown below and paste it into your <strong>./models/bookinstance.js</strong> file. The <code>BookInstance</code> represents a specific copy of a book that someone might borrow, and includes information about whether the copy is available or on what date it is expected back, "imprint" or version details.</p> + +<pre class="brush: js">var mongoose = require('mongoose'); + +var Schema = mongoose.Schema; + +var BookInstanceSchema = new Schema( + { + book: { type: Schema.ObjectId, ref: 'Book', required: true }, //reference to the associated book + imprint: {type: String, required: true}, + status: {type: String, required: true, <strong>enum: ['Available', 'Maintenance', 'Loaned', 'Reserved']</strong>, <strong>default: 'Maintenance'</strong>}, + due_back: {type: Date, <strong>default: Date.now</strong>} + } +); + +// Virtual for bookinstance's URL +BookInstanceSchema +.virtual('url') +.get(function () { + return '/catalog/bookinstance/' + this._id; +}); + +//Export model +module.exports = mongoose.model('BookInstance', BookInstanceSchema);</pre> + +<p>The new things we show here are the field options:</p> + +<ul> + <li><code>enum</code>: This allows us to set the allowed values of a string. In this case we use it to specify the availability status of our books (using an enum means that we can prevent mis-spellings and arbitrary values for our status)</li> + <li><code>default</code>: We use default to set the default status for newly created bookinstances to maintenance and the default <code>due_back</code> date to <code>now</code> (note how you can call the Date function when setting the date!)</li> +</ul> + +<p>Everything else should be familiar from our previous schema.</p> + +<h3 id="Genre_model_-_challenge!">Genre model - challenge!</h3> + +<p>Open your <strong>./models/genre.js</strong> file and create a schema for storing genres (the category of book, e.g. whether it is fiction or non-fiction, romance or military history, etc).</p> + +<p>The definition will be very similar to the other models:</p> + +<ul> + <li>The model should have a <code>String</code> SchemaType called <code>name</code> to describe the genre.</li> + <li>This name should be required and have between 3 and 100 characters.</li> + <li>Declare a <a href="#Virtual_properties">virtual</a> for the genre's URL, named <code>url</code>.</li> + <li>Export the model.</li> +</ul> + +<h2 id="Testing_—_create_some_items">Testing — create some items</h2> + +<p>That's it. We now have all models for the site set up!</p> + +<p>In order to test the models (and to create some example books and other items that we can use in our next articles) we'll now run an <em>independent</em> script to create items of each type:</p> + +<ol> + <li>Download (or otherwise create) the file <a href="https://raw.githubusercontent.com/hamishwillee/express-locallibrary-tutorial/master/populatedb.js">populatedb.js</a> inside your <em>express-locallibrary-tutorial</em> directory (in the same level as <code>package.json</code>). + + <div class="note"> + <p><strong>Note:</strong> You don't need to know how <a href="https://raw.githubusercontent.com/hamishwillee/express-locallibrary-tutorial/master/populatedb.js">populatedb.js</a> works; it just adds sample data into the database.</p> + </div> + </li> + <li>Enter the following commands in the project root to install the <em>async</em> module that is required by the script (we'll discuss this in later tutorials, ) + <pre class="brush: bash">npm install async --save</pre> + </li> + <li>Run the script using node in your command prompt, passing in the URL of your <em>MongoDB</em> database (the same one you replaced the <em>insert_your_database_url_here </em>placeholder with, inside <code>app.js</code> earlier): + <pre class="brush: bash">node populatedb <your mongodb url></pre> + </li> + <li>The script should run through to completion, displaying items as it creates them in the terminal.</li> +</ol> + +<div class="note"> +<p><strong>Tip:</strong> Go to your database on <a href="https://mlab.com/home">mLab</a>. You should now be able to drill down into individual collections of Books, Authors, Genres and BookInstances, and check out individual documents.</p> +</div> + +<h2 id="Summary">Summary</h2> + +<p>In this article we've learned a bit about databases and ORMs on Node/Express, and a lot about how Mongoose schema and models are defined. We then used this information to design and implement <code>Book</code>, <code>BookInstance</code>, <code>Author</code> and <code>Genre</code> models for the <em>LocalLibrary</em> website.</p> + +<p>Last of all we tested our models by creating a number of instances (using a standalone script). In the next article we'll look at creating some pages to display these objects.</p> + +<h2 id="See_also">See also</h2> + +<ul> + <li><a href="https://expressjs.com/en/guide/database-integration.html">Database integration</a> (Express docs)</li> + <li><a href="http://mongoosejs.com/">Mongoose website</a> (Mongoose docs)</li> + <li><a href="http://mongoosejs.com/docs/guide.html">Mongoose Guide</a> (Mongoose docs)</li> + <li><a href="http://mongoosejs.com/docs/validation.html">Validation</a> (Mongoose docs)</li> + <li><a href="http://mongoosejs.com/docs/schematypes.html">Schema Types</a> (Mongoose docs)</li> + <li><a href="http://mongoosejs.com/docs/models.html">Models</a> (Mongoose docs)</li> + <li><a href="http://mongoosejs.com/docs/queries.html">Queries</a> (Mongoose docs)</li> + <li><a href="http://mongoosejs.com/docs/populate.html">Population</a> (Mongoose docs)</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/skeleton_website", "Learn/Server-side/Express_Nodejs/routes", "Learn/Server-side/Express_Nodejs")}}</p> + +<p> </p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction">Express/Node introduction</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/development_environment">Setting up a Node (Express) development environment</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">Express Tutorial: The Local Library website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website">Express Tutorial Part 2: Creating a skeleton website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/mongoose">Express Tutorial Part 3: Using a Database (with Mongoose)</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/routes">Express Tutorial Part 4: Routes and controllers</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express Tutorial Part 5: Displaying library data</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms">Express Tutorial Part 6: Working with forms</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/deployment">Express Tutorial Part 7: Deploying to production</a></li> +</ul> + +<p> </p> diff --git a/files/ko/learn/server-side/express_nodejs/routes/index.html b/files/ko/learn/server-side/express_nodejs/routes/index.html new file mode 100644 index 0000000000..8d8618ca98 --- /dev/null +++ b/files/ko/learn/server-side/express_nodejs/routes/index.html @@ -0,0 +1,639 @@ +--- +title: 'Express Tutorial Part 4: Routes and controllers' +slug: Learn/Server-side/Express_Nodejs/routes +translation_of: Learn/Server-side/Express_Nodejs/routes +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/mongoose", "Learn/Server-side/Express_Nodejs/Displaying_data", "Learn/Server-side/Express_Nodejs")}}</div> + +<p class="summary">이 튜토리얼에서 우리는 더미 핸들러 함수를 이용해 최종적으로 <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">LocalLibrary</a> 웹사이트에 쓰이게 될 모든 리소스 종단점라우팅 모듈 (url 핸들링 코드)를 설정해 볼 것입니다.이 작업을 통해 우리는 향후 문서에 쓰일 함수들을 모듈화된 라우트 핸들링 코드 구조로 제작하는 법을 배울 수 있습니다.또한 Express를 이용해 모듈화된 라우팅방법을 잘 이해할 수 있게 될 것입니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">사전조건:</th> + <td><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction">Express/Node introduction</a>를 먼저 구독해주세요.이전 강의 주제를 완료해 주세요.( <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/mongoose">Express Tutorial Part3 : Mongoose Database 와 연동하기</a>)</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td> + <p> 간단한 라우팅 함수 구현.</p> + + <p>모든 URL 종단점 구성해보기.</p> + </td> + </tr> + </tbody> +</table> + +<h2 id="개요">개요</h2> + +<p>지난 튜토리얼에서 우리는 데이터베이스와의 상호작용을 위해서 Mongoose 모델을 정의 했으며 초기 도서관 기록들을 만들기 위해 단 하나의 스크립트 파일을 사용했습니다.이것으로 우리는 이제 사용자에게 정보를 제공을 위한 코드를 작성할 수 있게 되었습니다. 첫번째로 해야할 일은 어떠한 정보를 웹사이트 페이지에 노출시킬 지 정하는 것입니다.그 다음에 정보들을 반환하기 위한 적절한 URL을 정의하게 될 것입니다.</p> + +<p>하단의 다이어그램은 HTTP를 통해 정보를 요청/반환을 작업할 경우 실현시켜야 하는 정보와 객체들의 주요 흐름을 나타내고 있습니다.In addition to the views and routes the diagram shows "controllers" — functions that separate out the code to route requests from the code that actually processes requests.</p> + +<p> </p> + +<p>`이미 작성한 모델들을 제외한 우리가 앞으로 작성할 목록은 :</p> + +<ul> + <li>"Routes" to forward the supported requests (and any information encoded in request URLs) to the appropriate controller functions.</li> + <li>"라우트들"는 지원된 요청(요청 URL에 어떤 인코딩된 정보)들을 알맞은 Controller 함수들로 보낸다.</li> + <li>Controller functions to get the requested data from the models, create an HTML page displaying the data, and return it to the user to view in the browser.</li> + <li>Controller 함수는 모델로부터 요청된 데이터를 얻어내거나 , 데이터를 나타내는 HTML 페이지를 내고, 이것을 브라우져의 화면으로 사용자에게 전달한다.</li> + <li>Views (templates) used by the controllers to render the data.</li> + <li>View들(템플릿들)은 데이터를 렌더링하는 컨트롤러에 의해서 사용된다. </li> +</ul> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14456/MVC%20Express.png" style="height: 460px; width: 800px;"></p> + +<p>Ultimately we might have pages to show lists and detail information for books, genres, authors and bookinstances, along with pages to create, update, and delete records. That's a lot to document in one article. Therefore most of this article will concentrate on setting up our routes and controllers to return "dummy" content. We'll extend the controller methods in our subsequent articles to work with model data.</p> + +<p>The first section below provides a brief "primer" on how to use the Express "Router" middleware. We'll then use that knowledge in the following sections when we set up the LocalLibrary routes.</p> + +<h2 id="Routes_primer">Routes primer</h2> + +<p>A route is a section of Express code that associates an HTTP verb (<code>GET</code>, <code>POST</code>, <code>PUT</code>, <code>DELETE</code>, etc.), an URL path/pattern, and a function that is called to handle that pattern.</p> + +<p>There are several ways to create routes. For this tutorial we're going to use the <code><a href="http://expressjs.com/en/guide/routing.html#express-router">express.Router</a></code> middleware as it allows us to group the route handlers for a particular part of a site together and access them using a common route-prefix. We'll keep all our library-related routes in a "catalog" module, and, if we add routes for handling user accounts or other functions, we can keep them grouped separately.</p> + +<div class="note"> +<p><strong>Note:</strong> We discussed Express application routes briefly in our <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction#Creating_route_handlers">Express Introduction > Creating route handlers</a>. Other than providing better support for modularization (as discussed in the first subsection below), using <em>Router</em> is very similar to defining routes directly on the <em>Express application object</em>.</p> +</div> + +<p>The rest of this section provides an overview of how the <code>Router</code> can be used to define the routes.</p> + +<h3 id="분리된_라우트_모듈들의_사용과_정의(Defining_and_using_separate_route_modules)">분리된 라우트 모듈들의 사용과 정의(Defining and using separate route modules)</h3> + +<p>The code below provides a concrete example of how we can create a route module and then use it in an <em>Express</em> application.</p> + +<p>아래 코드는 우리가 어떻게 라우트 모듈을 생성하고 Express 어플리케이션에서 사용할 것인지에 대한 구체적인 예를 보여준다.</p> + +<p>First we create routes for a wiki in a module named <strong>wiki.js</strong>. The code first imports the Express application object, uses it to get a <code>Router</code> object and then adds a couple of routes to it using the <code>get()</code> method. Last of all the module exports the <code>Router</code> object.</p> + +<p>첫번재 우리는 wiki.js 를 이름을 가진 모듈에서 위키를 위한 라우트를 만든다. 첫번째 코드에서 Express 어플리케이션 객체가 중요하고, 이 객체를 라우트 오브젝트를 얻기 위해서 사용하고, get()메서드를 사용하여 라우트는 2개를 추가한다. 모듈에서 마지막에는 라우트 객체를 Export한다.</p> + +<pre class="brush: js"><code>// wiki.js - Wiki route module + +var express = require('express') +var router = express.Router() + +// Home page route +router.get('/', function (req, res) { + res.send('Wiki home page') +}) + +// About page route +router.get('/about', function (req, res) { + res.send('About this wiki') +}) + +module.exports = router</code> + +</pre> + +<div class="note"> +<p><strong>Note:</strong> Above we are defining our route handler callbacks directly in the router functions. In the LocalLibrary we'll define these callbacks in a separate controller module.</p> +</div> + +<p>To use the router module in our main app file we first <code>require()</code> the route module (<strong>wiki.js</strong>). We then call <code>use()</code> on the <em>Express</em> application to add the Router to the middleware handling path, specifying an URL path of 'wiki'.</p> + +<pre class="brush: js"><code>var wiki = require('./wiki.js') +// ... +app.use('/wiki', wiki)</code></pre> + +<p>The two routes defined in our wiki route module are then accessible from <code>/wiki/</code> and <code>/wiki/about/</code>.</p> + +<p>wiki 라우트 모듈에서 정희 두개의 라우트를 정의되면 /wiki그리고 /wiki/about/ 으로 접근가능해진다.</p> + +<h3 id="라우트_함수들(Route_functions)">라우트 함수들(Route functions)</h3> + +<p>Our module above defines a couple of typical route functions. The "about" route (reproduced below) is defined using the <code>Router.get()</code> method, which responds only to HTTP GET requests. The first argument to this method is the URL path while the second is a callback function that will be invoked if an HTTP GET request with the path is received.</p> + +<pre class="brush: js"><code>router.get('/about', function (req, res) { + res.send('About this wiki') +})</code> +</pre> + +<p>The callback takes three arguments (usually named as shown: <code>req</code>, <code>res</code>, <code>next</code>), that will contain the HTTP Request object, HTTP response, and the <em>next</em> function in the middleware chain.</p> + +<div class="note"> +<p><strong>Note:</strong> Router functions are <a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction#Using_middleware">Express middleware</a>, which means that they must either complete (respond to) the request or call the next function in the chain. In the case above we complete the request, so the <code>next</code> argument is not actually used.</p> +</div> + +<p>The callback function here calls <code><a href="https://expressjs.com/en/4x/api.html#res.send">send()</a></code> on the response to return the string "About this wiki" when we receive a GET request with the path ('<code>/about'</code>). There are a <a href="https://expressjs.com/en/guide/routing.html#response-methods">number of other response methods</a> for ending the request/response cycle. For example, you could call <code><a href="https://expressjs.com/en/4x/api.html#res.json">res.json()</a></code> to send a JSON response or <code><a href="https://expressjs.com/en/4x/api.html#res.sendFile">res.sendFile()</a></code> to send a file. The response method that we'll be using most often as we build up the library is <a href="https://expressjs.com/en/4x/api.html#res.render">render()</a>, which creates and returns HTML files using templates and data—we'll talk a lot more about that in a later article!</p> + +<h3 id="HTTP_verbs">HTTP verbs</h3> + +<p>The example routes above use the <code>Router.get()</code> method to respond to HTTP GET requests with a certain path.</p> + +<p>The <code>Router</code> also provides route methods for all the other HTTP verbs, that are mostly used in exactly the same way: <code>post()</code>, <code>put()</code>, <code>delete()</code>, <code>options()</code>, <code>trace()</code>, <code>copy()</code>, <code>lock()</code>, <code>mkcol()</code>, <code>move()</code>, <code>purge()</code>, <code>propfind()</code>, <code>proppatch()</code>, <code>unlock()</code>, <code>report()</code>, <code>mkactivity()</code>, <code>checkout()</code>, <code>merge()</code>, <code>m-</code><code>search()</code>, <code>notify()</code>, <code>subscribe()</code>, <code>unsubscribe()</code>, <code>patch()</code>, <code>search()</code>, and <code>connect()</code>.</p> + +<p>For example, the code below behaves just like the previous <code>/about</code> route, but only responds to HTTP POST requests.</p> + +<pre class="brush: js"><code>router.post('/about', function (req, res) { + res.send('About this wiki') +})</code></pre> + +<h3 id="라우트_경로들(Route_paths)">라우트 경로들(Route paths)</h3> + +<p>The route paths define the endpoints at which requests can be made. The examples we've seen so far have just been strings, and are used exactly as written: '/', '/about', '/book', '/any-random.path'.</p> + +<p>Route paths can also be string patterns. String patterns use a subset of regular expression syntax to define <em>patterns</em> of endpoints that will be matched. The subset is listed below (note that the hyphen (<code>-</code>) and the dot (<code>.</code>) are interpreted literally by string-based paths):</p> + +<ul> + <li>? : The endpoint must have 0 or more of the preceding character. E.g. a route path of <code>'/ab?cd'</code> will match endpoints <code>acd</code> , <code>abcd</code>, <code>abbcd</code> etc.</li> + <li>+ : The endpoint must have 1 or more of the preceding character. E.g. a route path of <code>'/ab+cd'</code> will match endpoints <code>abcd</code>, <code>abbcd</code>, <code>abbbcd</code>, and so on.</li> + <li>* : The endpoint may have an arbitrary string where the * character is placed. E.g. a route path of <code>'ab*cd'</code> will match endpoints <code>abcd</code>, <code>abXcd</code>, <code>abSOMErandomTEXTcd</code>, and so on.</li> + <li>() : Grouping match on a set of characters to perform another operation on. E.g. <code>'/ab(cd)?e'</code> will peform a ? match on (cd) —it will match <code>abe</code>, <code>abcde</code>, <code>abcdcde</code>, and so on.</li> +</ul> + +<p>The route paths can also be JavaScript <a href="/en-US/docs/Web/JavaScript/Guide/Regular_Expressions">regular expressions</a>. For example, the route path below will match match <code>catfish </code>and <code>dogfish</code>, but not <code>catflap</code>, <code>catfishhead</code>, and so on. Note that the path for a regular expression uses regular expression syntax (it is not a quoted string as in the previous cases).</p> + +<pre class="brush: js"><code>app.get(/.*fish$/, function (req, res) { + ... +})</code></pre> + +<div class="note"> +<p><strong>Note:</strong> Most of our routes for the LocalLibrary will simply use strings and not string patterns and regular expressions. We'll also use route parameters as discussed in the next section.</p> +</div> + +<h3 id="라우트_파라미터들(Route_parameters)">라우트 파라미터들(Route parameters)</h3> + +<p>Route parameters are <em>named URL segments</em> used to capture the values specified at their position in the URL. The named segments are prefixed with a colon and then the name (e.g. <code>/<strong>:</strong>your_parameter_name/</code>. The captured values are stored in the <code>req.params</code> object using the parameter names as keys (e.g. <code>req.params.your_parameter_name</code>).</p> + +<p>So for example, consider a URL encoded to contain information about users and books: <code>http://localhost:3000/users/34/books/8989</code>. We can extract this information as shown below, with the <code>userId</code> and <code>bookId</code> path parameters:</p> + +<pre><code>app.get('/users/:userId/books/:bookId', function (req, res) { + // Access userId via: req.params.userId + // Access bookId via: req.params.bookId + res.send(req.params) +}) +</code></pre> + +<p>The names of route parameters must be made up of “word characters” (A-Z, a-z, 0-9, and _).</p> + +<div class="note"> +<p><strong>Note:</strong> The URL <em>/book/create</em> will be matched by a route like <code>/book/:bookId</code> (which will extract a "bookId" value of '<code>create</code>'). The first route that matches an incoming URL will be used, so if you want to process <code>/book/create</code> URLs separately, their route handler must be defined before your <code>/book/:bookId</code> route.</p> +</div> + +<p>That's all you need to get started with routes - if needed you can find more information in the Express docs: <a href="http://expressjs.com/en/starter/basic-routing.html">Basic routing</a> and <a href="http://expressjs.com/en/guide/routing.html">Routing guide</a>. The following sections show how we'll set up our routes and controllers for the LocalLibrary.</p> + +<h2 id="Routes_needed_for_the_LocalLibrary">Routes needed for the LocalLibrary</h2> + +<p>The URLs that we're ultimately going to need for our pages are listed below, where <em>object</em> is replaced by the name of each of our models (book, bookinstance, genre, author), <em>objects</em> is the plural of object, and <em>id</em> is the unique instance field (<code>_id</code>) that is given to each Mongoose model instance by default.</p> + +<ul> + <li><code>catalog/</code> — The home/index page.</li> + <li><code>catalog/<objects>/</code> — The list of all books, bookinstances, genres, or authors (e.g. /<code>catalog/books/</code>, /<code>catalog/genres/</code>, etc.)</li> + <li><code>catalog/<object>/<em><id></em></code> — The detail page for a specific book, bookinstance, genre, or author with the given <code><em>_id</em></code> field value (e.g. <code>/catalog/book/584493c1f4887f06c0e67d37)</code>.</li> + <li><code>catalog/<object>/create</code> — The form to create a new book, bookinstance, genre, or author (e.g. <code>/catalog/book/create)</code>.</li> + <li><code>catalog/<object>/<em><id></em>/update</code> — The form to update a specific book, bookinstance, genre, or author with the given <code><em>_id</em></code> field value (e.g. <code>/catalog/book/584493c1f4887f06c0e67d37/update)</code>.</li> + <li><code>catalog/<object>/<em><id></em>/delete</code> — The form to delete a specific book, bookinstance, genre, author with the given <code><em>_id</em></code> field value (e.g. <code>/catalog/book/584493c1f4887f06c0e67d37/delete)</code>.</li> +</ul> + +<p>The first home page and list pages don't encode any additional information. While the results returned will depend on the model type and the content in the database, the queries run to get the information will always be the same (similarly the code run for object creation will always be similar).</p> + +<p>By contrast the other URLs are used to act on a specific document/model instance—these encode the identity of the item in the URL (shown as <code><em><id></em></code> above). We'll use path parameters to extract the encoded information and pass it to the route handler (and in a later article we'll use this to dynamically determine what information to get from the database). By encoding the information in our URL we only need one route for every resource of a particular type (e.g. one route to handle the display of every single book item).</p> + +<div class="note"> +<p><strong>Note</strong>: Express allows you to construct your URLs any way you like — you can encode information in the body of the URL as shown above or use URL <code>GET</code> parameters (e.g. <code>/book/?id=6</code>). Whichever approach you use, the URLs should be kept clean, logical and readable (<a href="https://www.w3.org/Provider/Style/URI">check out the W3C advice here</a>).</p> +</div> + +<p>Next we create our route handler callback functions and route code for all the above URLs.</p> + +<h2 id="Create_the_route-handler_callback_functions">Create the route-handler callback functions</h2> + +<p>Before we define our routes, we'll first create all the dummy/skeleton callback functions that they will invoke. The callbacks will be stored in separate "controller" modules for Books, BookInstances, Genres, and Authors (you can use any file/module structure, but this seems an appropriate granularity for this project).</p> + +<p>Start by creating a folder for our controllers in the project root (<strong>/controllers</strong>) and then create separate controller files/modules for handling each of the models:</p> + +<pre>/express-locallibrary-tutorial //the project root + <strong>/controllers</strong> + <strong>authorController.js</strong> + <strong>bookController.js</strong> + <strong>bookinstanceController.js</strong> + <strong>genreController.js</strong></pre> + +<h3 id="Author_controller">Author controller</h3> + +<p>Open the <strong>/controllers/authorController.js</strong> file and copy in the following code:</p> + +<pre class="brush: js">var Author = require('../models/author'); + +// Display list of all Authors +exports.author_list = function(req, res) { + res.send('NOT IMPLEMENTED: Author list'); +}; + +// Display detail page for a specific Author +exports.author_detail = function(req, res) { + res.send('NOT IMPLEMENTED: Author detail: ' + req.params.id); +}; + +// Display Author create form on GET +exports.author_create_get = function(req, res) { + res.send('NOT IMPLEMENTED: Author create GET'); +}; + +// Handle Author create on POST +exports.author_create_post = function(req, res) { + res.send('NOT IMPLEMENTED: Author create POST'); +}; + +// Display Author delete form on GET +exports.author_delete_get = function(req, res) { + res.send('NOT IMPLEMENTED: Author delete GET'); +}; + +// Handle Author delete on POST +exports.author_delete_post = function(req, res) { + res.send('NOT IMPLEMENTED: Author delete POST'); +}; + +// Display Author update form on GET +exports.author_update_get = function(req, res) { + res.send('NOT IMPLEMENTED: Author update GET'); +}; + +// Handle Author update on POST +exports.author_update_post = function(req, res) { + res.send('NOT IMPLEMENTED: Author update POST'); +}; +</pre> + +<p>The module first requires the model that we'll later be using to access and update our data. It then exports functions for each of the URLs we wish to handle (the create, update and delete operations use forms, and hence also have additional methods for handling form post requests — we'll discuss those methods in the "forms article" later on).</p> + +<p>All the functions have the standard form of an <em>Express middleware function</em>, with arguments for the request, response, and the <code>next</code> function to be called if the method does not complete the request cycle (in all these cases it does!). The methods simply return a string indicating that the associated page has not yet been created. If a controller function is expected to receive path parameters, these are included in the message string.</p> + +<h4 id="BookInstance_controller">BookInstance controller</h4> + +<p>Open the <strong>/controllers/bookinstanceController.js</strong> file and copy in the following code (this follows an identical pattern to the <code>Author</code> controller module):</p> + +<pre class="brush: js">var BookInstance = require('../models/bookinstance'); + +// Display list of all BookInstances +exports.bookinstance_list = function(req, res) { + res.send('NOT IMPLEMENTED: BookInstance list'); +}; + +// Display detail page for a specific BookInstance +exports.bookinstance_detail = function(req, res) { + res.send('NOT IMPLEMENTED: BookInstance detail: ' + req.params.id); +}; + +// Display BookInstance create form on GET +exports.bookinstance_create_get = function(req, res) { + res.send('NOT IMPLEMENTED: BookInstance create GET'); +}; + +// Handle BookInstance create on POST +exports.bookinstance_create_post = function(req, res) { + res.send('NOT IMPLEMENTED: BookInstance create POST'); +}; + +// Display BookInstance delete form on GET +exports.bookinstance_delete_get = function(req, res) { + res.send('NOT IMPLEMENTED: BookInstance delete GET'); +}; + +// Handle BookInstance delete on POST +exports.bookinstance_delete_post = function(req, res) { + res.send('NOT IMPLEMENTED: BookInstance delete POST'); +}; + +// Display BookInstance update form on GET +exports.bookinstance_update_get = function(req, res) { + res.send('NOT IMPLEMENTED: BookInstance update GET'); +}; + +// Handle bookinstance update on POST +exports.bookinstance_update_post = function(req, res) { + res.send('NOT IMPLEMENTED: BookInstance update POST'); +}; +</pre> + +<h4 id="Genre_controller">Genre controller</h4> + +<p>Open the <strong>/controllers/genreController.js</strong> file and copy in the following text (this follows an identical pattern to the <code>Author</code> and <code>BookInstance</code> files):</p> + +<pre class="brush: js">var Genre = require('../models/genre'); + +// Display list of all Genre +exports.genre_list = function(req, res) { + res.send('NOT IMPLEMENTED: Genre list'); +}; + +// Display detail page for a specific Genre +exports.genre_detail = function(req, res) { + res.send('NOT IMPLEMENTED: Genre detail: ' + req.params.id); +}; + +// Display Genre create form on GET +exports.genre_create_get = function(req, res) { + res.send('NOT IMPLEMENTED: Genre create GET'); +}; + +// Handle Genre create on POST +exports.genre_create_post = function(req, res) { + res.send('NOT IMPLEMENTED: Genre create POST'); +}; + +// Display Genre delete form on GET +exports.genre_delete_get = function(req, res) { + res.send('NOT IMPLEMENTED: Genre delete GET'); +}; + +// Handle Genre delete on POST +exports.genre_delete_post = function(req, res) { + res.send('NOT IMPLEMENTED: Genre delete POST'); +}; + +// Display Genre update form on GET +exports.genre_update_get = function(req, res) { + res.send('NOT IMPLEMENTED: Genre update GET'); +}; + +// Handle Genre update on POST +exports.genre_update_post = function(req, res) { + res.send('NOT IMPLEMENTED: Genre update POST'); +}; +</pre> + +<h4 id="Book_controller">Book controller</h4> + +<p>Open the <strong>/controllers/bookController.js</strong> file and copy in the following code. This follows the same pattern as the other controller modules, but additionally has an <code>index()</code> function for displaying the site welcome page:</p> + +<pre class="brush: js">var Book = require('../models/book'); + +<strong>exports.index = function(req, res) { + res.send('NOT IMPLEMENTED: Site Home Page'); +};</strong> + +// Display list of all books +exports.book_list = function(req, res) { + res.send('NOT IMPLEMENTED: Book list'); +}; + +// Display detail page for a specific book +exports.book_detail = function(req, res) { + res.send('NOT IMPLEMENTED: Book detail: ' + req.params.id); +}; + +// Display book create form on GET +exports.book_create_get = function(req, res) { + res.send('NOT IMPLEMENTED: Book create GET'); +}; + +// Handle book create on POST +exports.book_create_post = function(req, res) { + res.send('NOT IMPLEMENTED: Book create POST'); +}; + +// Display book delete form on GET +exports.book_delete_get = function(req, res) { + res.send('NOT IMPLEMENTED: Book delete GET'); +}; + +// Handle book delete on POST +exports.book_delete_post = function(req, res) { + res.send('NOT IMPLEMENTED: Book delete POST'); +}; + +// Display book update form on GET +exports.book_update_get = function(req, res) { + res.send('NOT IMPLEMENTED: Book update GET'); +}; + +// Handle book update on POST +exports.book_update_post = function(req, res) { + res.send('NOT IMPLEMENTED: Book update POST'); +}; +</pre> + +<h2 id="Create_the_catalog_route_module">Create the catalog route module</h2> + +<p>Next we create <em>routes</em> for all the URLs <a href="#local_libary_routes">needed by the LocalLibrary website</a>, which will call the controller functions we defined in the previous section.</p> + +<p>The skeleton already has a <strong>./routes</strong> folder containing routes for the <em>index</em> and <em>users</em>. Create another route file — <strong>catalog.js</strong> — inside this folder, as shown.</p> + +<pre>/express-locallibrary-tutorial //the project root + /routes + index.js + users.js + <strong>catalog.js</strong></pre> + +<p>Open <strong>/routes/</strong><strong>catalog.js</strong> and copy in the code below:</p> + +<pre class="brush: js"><strong>var express = require('express'); +var router = express.Router(); +</strong> +// Require controller modules +var book_controller = require('../controllers/bookController'); +var author_controller = require('../controllers/authorController'); +var genre_controller = require('../controllers/genreController'); +var book_instance_controller = require('../controllers/bookinstanceController'); + +/// BOOK ROUTES /// + +/* GET catalog home page. */ +router.get('/', book_controller.index); + +/* GET request for creating a Book. NOTE This must come before routes that display Book (uses id) */ +router.get('/book/create', book_controller.book_create_get); + +/* POST request for creating Book. */ +router.post('/book/create', book_controller.book_create_post); + +/* GET request to delete Book. */ +router.get('/book/:id/delete', book_controller.book_delete_get); + +// POST request to delete Book +router.post('/book/:id/delete', book_controller.book_delete_post); + +/* GET request to update Book. */ +router.get('/book/:id/update', book_controller.book_update_get); + +// POST request to update Book +router.post('/book/:id/update', book_controller.book_update_post); + +/* GET request for one Book. */ +router.get('/book/:id', book_controller.book_detail); + +/* GET request for list of all Book items. */ +router.get('/books', book_controller.book_list); + +/// AUTHOR ROUTES /// + +/* GET request for creating Author. NOTE This must come before route for id (i.e. display author) */ +router.get('/author/create', author_controller.author_create_get); + +/* POST request for creating Author. */ +router.post('/author/create', author_controller.author_create_post); + +/* GET request to delete Author. */ +router.get('/author/:id/delete', author_controller.author_delete_get); + +// POST request to delete Author +router.post('/author/:id/delete', author_controller.author_delete_post); + +/* GET request to update Author. */ +router.get('/author/:id/update', author_controller.author_update_get); + +// POST request to update Author +router.post('/author/:id/update', author_controller.author_update_post); + +/* GET request for one Author. */ +router.get('/author/:id', author_controller.author_detail); + +/* GET request for list of all Authors. */ +router.get('/authors', author_controller.author_list); + +/// GENRE ROUTES /// + +/* GET request for creating a Genre. NOTE This must come before route that displays Genre (uses id) */ +router.get('/genre/create', genre_controller.genre_create_get); + +/* POST request for creating Genre. */ +router.post('/genre/create', genre_controller.genre_create_post); + +/* GET request to delete Genre. */ +router.get('/genre/:id/delete', genre_controller.genre_delete_get); + +// POST request to delete Genre +router.post('/genre/:id/delete', genre_controller.genre_delete_post); + +/* GET request to update Genre. */ +router.get('/genre/:id/update', genre_controller.genre_update_get); + +// POST request to update Genre +router.post('/genre/:id/update', genre_controller.genre_update_post); + +/* GET request for one Genre. */ +router.get('/genre/:id', genre_controller.genre_detail); + +/* GET request for list of all Genre. */ +router.get('/genres', genre_controller.genre_list); + +/// BOOKINSTANCE ROUTES /// + +/* GET request for creating a BookInstance. NOTE This must come before route that displays BookInstance (uses id) */ +router.get('/bookinstance/create', book_instance_controller.bookinstance_create_get); + +/* POST request for creating BookInstance. */ +router.post('/bookinstance/create', book_instance_controller.bookinstance_create_post); + +/* GET request to delete BookInstance. */ +router.get('/bookinstance/:id/delete', book_instance_controller.bookinstance_delete_get); + +// POST request to delete BookInstance +router.post('/bookinstance/:id/delete', book_instance_controller.bookinstance_delete_post); + +/* GET request to update BookInstance. */ +router.get('/bookinstance/:id/update', book_instance_controller.bookinstance_update_get); + +// POST request to update BookInstance +router.post('/bookinstance/:id/update', book_instance_controller.bookinstance_update_post); + +/* GET request for one BookInstance. */ +router.get('/bookinstance/:id', book_instance_controller.bookinstance_detail); + +/* GET request for list of all BookInstance. */ +router.get('/bookinstances', book_instance_controller.bookinstance_list); + +<strong>module.exports = router;</strong> +</pre> + +<p>The module requires Express and then uses it to create a <code>Router</code> object. The routes are all set up on the router, which is then exported.</p> + +<p>The routes are defined either using <code>.get()</code> or <code>.post()</code> methods on the router object. All the paths are defined using strings (we don't use string patterns or regular expressions), routes that act on some specific resource (e.g. book) use path parameters to get the object id from the URL.</p> + +<p>The handler functions are all imported from the controller modules we created in the previous section.</p> + +<h3 id="Update_the_index_route_module">Update the index route module</h3> + +<p>We've set up all our new routes, but we still have a route to the original page. Let's instead redirect this to the new index page that we've created at the path '/catalog'.</p> + +<p>Open <strong>/routes/index.js</strong> and replace the existing route with the function below.</p> + +<pre class="brush: js">/* GET home page. */ +router.get('/', function(req, res) { + res.redirect('/catalog'); +});</pre> + +<div class="note"> +<p><strong>Note:</strong> This is our first use of the <a href="https://expressjs.com/en/4x/api.html#res.redirect">redirect()</a> response method. This redirects to the specified page, by default sending HTTP status code "302 Found". You can change the status code returned if needed, and supply either absolute or relative paths.</p> +</div> + +<h3 id="Update_app.js">Update app.js</h3> + +<p>The last step is to add the routes to the middleware chain. We do this in <code>app.js</code>.</p> + +<p>Open <strong>app.js</strong> and require the catalog route below the other routes (add the third line shown below, underneath the other two):</p> + +<pre class="brush: js">var index = require('./routes/index'); +var users = require('./routes/users'); +<strong>var catalog = require('./routes/catalog'); //Import routes for "catalog" area of site</strong></pre> + +<p>Next, add the catalog route to the middleware stack below the other routes (add the third line shown below, underneath the other two):</p> + +<pre class="brush: js">app.use('/', index); +app.use('/users', users); +<strong>app.use('/catalog', catalog); // Add catalog routes to middleware chain.</strong></pre> + +<div class="note"> +<p><strong>Note:</strong> We have added our catalog module at a path <code>'/catalog'</code>. This is prepended to all of the paths defined in the catalog module. So for example, to access a list of books, the URL will be: <code>/catalog/books/</code>.</p> +</div> + +<p>That's it. We should now have routes and skeleton functions enabled for all the URLs that we will eventually support on the LocalLibrary website.</p> + +<h3 id="Testing_the_routes">Testing the routes</h3> + +<p>To test the routes, first start the website using your usual approach</p> + +<ul> + <li>The default method + <pre class="brush: bash"><code>//Windows +SET DEBUG=express-locallibrary-tutorial:* & npm start + +// Mac OS or Linux +DEBUG=express-locallibrary-tutorial:* npm start</code> +</pre> + </li> + <li>If you previously set up <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website">nodemon</a>, you can instead use: + <pre><code>//Windows +SET DEBUG=express-locallibrary-tutorial:* & npm <strong>run devstart</strong> + +// Mac OS or Linux +</code>DEBUG=express-locallibrary-tutorial:* npm <strong style="font-family: inherit; font-size: 1rem;">run devstart</strong> +</pre> + </li> +</ul> + +<p>Then navigate to a number of LocalLibrary URLs, and verify that you don't get an error page (HTTP 404). A small set of URLs are listed below for your convenience:</p> + +<ul> + <li><a href="http://localhost:3000/">http://localhost:3000/</a></li> + <li><a href="http://localhost:3000/catalog">http://localhost:3000/catalog</a></li> + <li><a href="http://localhost:3000/catalog/books">http://localhost:3000/catalog/books</a></li> + <li><a href="http://localhost:3000/catalog/bookinstances/">http://localhost:3000/catalog/bookinstances/</a></li> + <li><a href="http://localhost:3000/catalog/authors/">http://localhost:3000/catalog/authors/</a></li> + <li><a href="http://localhost:3000/catalog/genres/">http://localhost:3000/catalog/genres/</a></li> + <li><a href="http://localhost:3000/catalog/book/5846437593935e2f8c2aa226/">http://localhost:3000/catalog/book/5846437593935e2f8c2aa226</a></li> + <li><a href="http://localhost:3000/catalog/book/create">http://localhost:3000/catalog/book/create</a></li> +</ul> + +<h2 id="Summary">Summary</h2> + +<p>We've now created all the routes for our site, along with dummy controller functions that we can populate with a full implementation in later articles. Along the way we've learned a lot of fundamental information about Express routes, and some approaches for structuring our routes and controllers.</p> + +<p>In our next article we'll create a proper welcome page for the site, using views (templates) and information stored in our models.</p> + +<h2 id="See_also">See also</h2> + +<ul> + <li><a href="http://expressjs.com/en/starter/basic-routing.html">Basic routing</a> (Express docs)</li> + <li><a href="http://expressjs.com/en/guide/routing.html">Routing guide</a> (Express docs)</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/mongoose", "Learn/Server-side/Express_Nodejs/Displaying_data", "Learn/Server-side/Express_Nodejs")}}</p> diff --git a/files/ko/learn/server-side/express_nodejs/개발_환경/index.html b/files/ko/learn/server-side/express_nodejs/개발_환경/index.html new file mode 100644 index 0000000000..b8c8db8ffa --- /dev/null +++ b/files/ko/learn/server-side/express_nodejs/개발_환경/index.html @@ -0,0 +1,403 @@ +--- +title: Node 개발 환경을 설치하기 +slug: Learn/Server-side/Express_Nodejs/개발_환경 +tags: + - CodingScripting + - Express + - Node + - nodejs + - npm + - 개발 환경 + - 배움 + - 서버-사이드 + - 인트로 + - 초보자 +translation_of: Learn/Server-side/Express_Nodejs/development_environment +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/Introduction", "Learn/Server-side/Express_Nodejs/Tutorial_local_library_website", "Learn/Server-side/Express_Nodejs")}}</div> + +<p class="summary">이제 Express에 관한 내용을 알았으니, Windows, Linux (Ubuntu), 그리고 macOS 에서의 Node/Express 개발 환경을 설정하고 테스트하는 법을 보여드리겠습니다. 사용중인 운영 체제가 무엇이든 간에, 이 글은 당신에게 Express 앱 개발을 시작할 수 있도록 필요한 내용을 제공합니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">전제 조건:</th> + <td>터미널 혹은 명령어 창을 여는 방법. 당신의 개발 컴퓨터의 운영 체제에 소프트웨어 패키지를 설치하는 방법을 알고 있어야 합니다.</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>당신의 컴퓨터에 Express (X.XX) 을 위한 개발 환경을 설치하는 것.</td> + </tr> + </tbody> +</table> + +<h2 id="Express_개발_환경_개요">Express 개발 환경 개요</h2> + +<p><em>Node</em> and <em>Express</em> make it very easy to set up your computer in order to start developing web applications. This section provides an overview of what tools are needed, explains some of the simplest methods for installing Node (and Express) on Ubuntu, macOS, and Windows, and shows how you can test your installation.</p> + +<h3 id="Express_개발_환경이란_무엇입니까">Express 개발 환경이란 무엇입니까?</h3> + +<p>The <em>Express</em> development environment includes an installation of <em>Nodejs</em>, the <em>NPM package manager</em>, and (optionally) the <em>Express Application Generator</em> on your local computer.</p> + +<p><em>Node</em> and the <em>NPM</em> package manager are installed together from prepared binary packages, installers, operating system package managers or from source (as shown in the following sections). <em>Express</em> is then installed by NPM as a dependency of your individual <em>Express</em> web applications (along with other libraries like template engines, database drivers, authentication middleware, middleware to serve static files, etc.)</p> + +<p><em>NPM</em> can also be used to (globally) install the <em>Express Application Generator</em>, a handy tool for creating skeleton <em>Express</em> web apps that follow the <a href="https://developer.mozilla.org/en-US/docs/Glossary/MVC">MVC pattern</a>. The application generator is optional because you don't <em>need</em> to use this tool to create apps that use Express, or construct Express apps that have the same architectural layout or dependencies. We'll be using it though, because it makes getting started a lot easier, and promotes a modular application structure.</p> + +<div class="note"> +<p><strong>Note:</strong> Unlike for some other web frameworks, the development environment does not include a separate development web server. In <em>Node</em>/<em>Express</em> a web application creates and runs its own web server!</p> +</div> + +<p>There are other peripheral tools that are part of a typical development environment, including <a href="/en-US/docs/Learn/Common_questions/Available_text_editors">text editors</a> or IDEs for editing code, and source control management tools like <a href="https://git-scm.com/">Git</a> for safely managing different versions of your code. We are assuming that you've already got these sorts of tools installed (in particular a text editor).</p> + +<h3 id="What_operating_systems_are_supported">What operating systems are supported?</h3> + +<p><em>Node</em> can be run on Windows, macOS, many "flavours" of Linux, Docker, etc. (there is a full list on the nodejs <a href="https://nodejs.org/en/download/">Downloads</a> page). Almost any personal computer should have the necessary performance to run Node during development. <em>Express</em> is run in a <em>Node</em> environment, and hence can run on any platform that runs <em>Node</em>.</p> + +<p>In this article we provide setup instructions for Windows, macOS, and Ubuntu Linux.</p> + +<h3 id="What_version_of_NodeExpress_should_you_use">What version of Node/Express should you use?</h3> + +<p>There are many <a href="https://nodejs.org/en/blog/release/">releases of Node</a> — newer releases contain bug fixes, support for more recent versions of ECMAScript (JavaScript) standards, and improvements to the Node APIs. </p> + +<p>Generally you should use the most recent <em>LTS (long-term supported)</em> release as this will be more stable than the "current" release while still having relatively recent features (and is still being actively maintained). You should use the <em>Current</em> release if you need a feature that is not present in the LTS version.</p> + +<p>For <em>Express</em> you should always use the latest version.</p> + +<h3 id="What_about_databases_and_other_dependencies">What about databases and other dependencies?</h3> + +<p>Other dependencies, such as database drivers, template engines, authentication engines, etc. are part of the application, and are imported into the application environment using the NPM package manager. We'll discuss them in later app-specific articles.</p> + +<h2 id="Node_설치하기">Node 설치하기</h2> + +<p>In order to use <em>Express</em> you will first have to install <em>Nodejs</em> and the <a href="https://docs.npmjs.com/">Node Package Manager (NPM)</a> on your operating system. The following sections explain the easiest way to install the Long Term Supported (LTS) version of Nodejs on Ubuntu Linux 16.04, macOS, and Windows 10.</p> + +<div class="note"> +<p><strong>Tip:</strong> The sections below show the easiest way to install <em>Node</em> and <em>NPM</em> on our target OS platforms. If you're using another OS or just want to see some of the other approaches for the current platforms then see <a href="https://nodejs.org/en/download/package-manager/">Installing Node.js via package manager</a> (nodejs.org).</p> +</div> + +<h3 id="Windows_and_macOS">Windows and macOS</h3> + +<p>Installing <em>Node</em> and <em>NPM</em> on Windows and macOS is straightforward because you can just use the provided installer:</p> + +<ol> + <li>Download the required installer: + <ol> + <li>Go to <a href="https://nodejs.org/en/">https://nodejs.org/en/</a></li> + <li>Select the button to download the LTS build that is "Recommended for most users".</li> + </ol> + </li> + <li>Install Node by double-clicking on the downloaded file and following the installation prompts.</li> +</ol> + +<h3 id="Ubuntu_18.04">Ubuntu 18.04</h3> + +<p>The easiest way to install the most recent LTS version of Node 10.x is to use the <a href="https://nodejs.org/en/download/package-manager/#debian-and-ubuntu-based-linux-distributions">package manager</a> to get it from the Ubuntu <em>binary distributions</em> repository. This can be done very simply by running the following two commands on your terminal:</p> + +<pre class="brush: bash">curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash - +sudo apt-get install -y nodejs +</pre> + +<div class="warning"> +<p><strong>Warning:</strong> Don't install directly from the normal Ubuntu repositories because they contain very old versions of node.</p> +</div> + +<ol> +</ol> + +<h3 id="Testing_your_Nodejs_and_NPM_installation">Testing your Nodejs and NPM installation</h3> + +<p>The easiest way to test that node is installed is to run the "version" command in your terminal/command prompt and check that a version string is returned:</p> + +<pre class="brush: bash">>node -v +v10.15.1</pre> + +<p>The <em>Nodejs</em> package manager <em>NPM</em> should also have been installed, and can be tested in the same way:</p> + +<pre class="brush: bash">>npm -v +6.4.1</pre> + +<p>As a slightly more exciting test let's create a very basic "pure node" server that simply prints out "Hello World" in the browser when you visit the correct URL in your browser:</p> + +<ol> + <li>Copy the following text into a file named <strong>hellonode.js</strong>. This uses pure <em>Node</em> features (nothing from Express) and some ES6 syntax: + + <pre class="brush: js">//Load HTTP module +const http = require("http"); +const hostname = '127.0.0.1'; +const port = 3000; + +//Create HTTP server and listen on port 3000 for requests +const server = http.createServer((req, res) => { + + //Set the response HTTP header with HTTP status and Content type + res.statusCode = 200; + res.setHeader('Content-Type', 'text/plain'); + res.end('Hello World\n'); +}); + +//listen for request on port 3000, and as a callback function have the port listened on logged +server.listen(port, hostname, () => { + console.log(`Server running at http://${hostname}:${port}/`); +}); +</pre> + + <p>The code imports the "http" module and uses it to create a server (<code>createServer()</code>) that listens for HTTP requests on port 3000. The script then prints a message to the console about what browser URL you can use to test the server. The <code>createServer()</code> function takes as an argument a callback function that will be invoked when an HTTP request is received — this simply returns a response with an HTTP status code of 200 ("OK") and the plain text "Hello World".</p> + + <div class="note"> + <p><strong>Note:</strong> Don't worry if you don't understand exactly what this code is doing yet! We'll explain our code in greater detail once we start using Express!</p> + </div> + </li> + <li>Start the server by navigating into the same directory as your <code>hellonode.js</code> file in your command prompt, and calling <code>node</code> along with the script name, like so: + <pre class="brush: bash">>node hellonode.js +Server running at http://127.0.0.1:3000/ +</pre> + </li> + <li>Navigate to the URL <a href="http://127.0.0.1:3000">http://127.0.0.1:3000 </a>. If everything is working, the browser should simply display the string "Hello World".</li> +</ol> + +<h2 id="Using_NPM">Using NPM</h2> + +<p>Next to <em>Node</em> itself, <a href="https://docs.npmjs.com/">NPM</a> is the most important tool for working with<em> Node </em>applications. NPM is used to fetch any packages (JavaScript libraries) that an application needs for development, testing, and/or production, and may also be used to run tests and tools used in the development process. </p> + +<div class="note"> +<p><strong>Note:</strong> From Node's perspective, <em>Express</em> is just another package that you need to install using NPM and then require in your own code.</p> +</div> + +<p>You can manually use NPM to separately fetch each needed package. Typically we instead manage dependencies using a plain-text definition file named <a href="https://docs.npmjs.com/files/package.json">package.json</a>. This file lists all the dependencies for a specific JavaScript "package", including the package's name, version, description, initial file to execute, production dependencies, development dependencies, versions of <em>Node</em> it can work with, etc. The <strong>package.json</strong> file should contain everything NPM needs to fetch and run your application (if you were writing a reusable library you could use this definition to upload your package to the npm respository and make it available for other users).</p> + +<h3 id="Adding_dependencies">Adding dependencies</h3> + +<p>The following steps show how you can use NPM to download a package, save it into the project dependencies, and then require it in a Node application.</p> + +<div class="note"> +<p><strong>Note:</strong> Here we show the instructions to fetch and install the <em>Express</em> package. Later on we'll show how this package, and others, are already specified for us using the <em>Express Application Generator</em>. This section is provided because it is useful to understand how NPM works and what is being created by the application generator.</p> +</div> + +<ol> + <li>First create a directory for your new application and navigate into it: + <pre class="brush: bash">mkdir myapp +cd myapp</pre> + </li> + <li>Use the npm <code>init</code> command to create a <strong>package.json</strong> file for your application. This command prompts you for a number of things, including the name and version of your application and the name of the initial entry point file (by default this is <strong>index.js</strong>). For now, just accept the defaults: + <pre class="brush: bash">npm init</pre> + + <p>If you display the <strong>package.json</strong> file (<code>cat package.json</code>), you will see the defaults that you accepted, ending with the license.</p> + + <pre class="brush: json">{ + "name": "myapp", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC" +} +</pre> + </li> + <li>Now install Express in the <code>myapp</code> directory and save it in the dependencies list of your <strong>package.json</strong> file</li> + <li> + <pre class="brush: bash">npm install express</pre> + + <p>The dependencies section of your <strong>package.json</strong> will now appear at the end of the <strong>package.json</strong> file and will include <em>Express</em>.</p> + + <pre class="brush: json">{ + "name": "myapp", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", +<strong> "dependencies": { + "express": "^4.16.4" + }</strong> +} +</pre> + </li> + <li>To use the Express library you call the <code>require()</code> function in your index.js file to include it in your application. Create this file now, in the root of the "myapp" application directory, and give it the following contents: + <pre class="brush: js">const express = require('express') +const app = express(); + +app.get('/', (req, res) => { + res.send('Hello World!') +}); + +app.listen(8000, () => { + console.log('Example app listening on port 8000!') +}); +</pre> + + <p>This code shows a minimal "HelloWorld" Express web application. This imports the "express" module using <code>require()</code> and uses it to create a server (<code>app</code>) that listens for HTTP requests on port 8000 and prints a message to the console explaining what browser URL you can use to test the server. The <code>app.get()</code> function only responds to HTTP <code>GET</code> requests with the specified URL path ('/'), in this case by calling a function to send our <em>Hello World!</em> message.</p> + </li> + <li>You can start the server by calling node with the script in your command prompt: + <pre class="brush: bash">>node index.js +Example app listening on port 8000 +</pre> + </li> + <li>Navigate to the URL (<a href="http://127.0.0.1:8000/">http://127.0.0.1:8000/</a>). If everything is working, the browser should simply display the string "Hello World!".</li> +</ol> + +<h3 id="Development_dependencies">Development dependencies</h3> + +<p>If a dependency is only used during development, you should instead save it as a "development dependency" (so that your package users don't have to install it in production). For example, to use the popular JavaScript Linting tool <a href="http://eslint.org/">eslint</a> you would call NPM as shown:</p> + +<pre class="brush: bash"><code>npm install eslint --save-dev</code></pre> + +<p>The following entry would then be added to your application's <strong>package.json</strong>:</p> + +<pre class="brush: js"> "devDependencies": { + "eslint": "^4.12.1" + } +</pre> + +<div class="note"> +<p><strong>Note:</strong> "<a href="https://en.wikipedia.org/wiki/Lint_(software)">Linters</a>" are tools that perform static analysis on software in order to recognise and report adherence/non-adherance to some set of coding best practice.</p> +</div> + +<h3 id="Running_tasks">Running tasks</h3> + +<p>In addition to defining and fetching dependencies you can also define <em>named</em> scripts in your <strong>package.json</strong> files and call NPM to execute them with the <a href="https://docs.npmjs.com/cli/run-script">run-script</a> command. This approach is commonly used to automate running tests and parts of the development or build toolchain (e.g., running tools to minify JavaScript, shrink images, LINT/analyse your code, etc).</p> + +<div class="note"> +<p><strong>Note:</strong> Task runners like <a href="http://gulpjs.com/">Gulp</a> and <a href="http://gruntjs.com/">Grunt</a> can also be used to run tests and other external tools.</p> +</div> + +<p>For example, to define a script to run the <em>eslint</em> development dependency that we specified in the previous section we might add the following script block to our <strong>package.json</strong> file (assuming that our application source is in a folder /src/js):</p> + +<pre class="brush: js">"scripts": { + ... + "lint": "eslint src/js" + ... +} +</pre> + +<p>To explain a little further, <code>eslint src/js</code> is a command that we could enter in our terminal/command line to run <code>eslint</code> on JavaScript files contained in the <code>src/js</code> directory inside our app directory. Including the above inside our app's package.json file provides a shortcut for this command — <code>lint</code>.</p> + +<p>We would then be able to run <em>eslint</em> using NPM by calling:</p> + +<pre class="brush: bash"><code>npm run-script lint +# OR (using the alias) +npm run lint</code> +</pre> + +<p>This example may not look any shorter than the original command, but you can include much bigger commands inside your npm scripts, including chains of multiple commands. You could identify a single npm script that runs all your tests at once.</p> + +<h2 id="Installing_the_Express_Application_Generator">Installing the Express Application Generator</h2> + +<p>The <a href="https://expressjs.com/en/starter/generator.html">Express Application Generator</a> tool generates an Express application "skeleton". Install the generator using NPM as shown (the <code>-g</code> flag installs the tool globally so that you can call it from anywhere):</p> + +<pre><code>npm install express-generator -g</code></pre> + +<p>To create an <em>Express</em> app named "helloworld" with the default settings, navigate to where you want to create it and run the app as shown:</p> + +<pre class="brush: bash">express helloworld</pre> + +<div class="note"> +<p><strong>Note: </strong>You can also specify the template library to use and a number of other settings. Use the <code>help</code> command to see all the options:</p> + +<pre class="brush: bash">express --help +</pre> +</div> + +<p>NPM will create the new Express app in a sub folder of your current location, displaying build progress on the console. On completion, the tool will display the commands you need to enter to install the Node dependencies and start the app.</p> + +<div class="note"> +<p>The new app will have a <strong>package.json</strong> file in its root directory. You can open this to see what dependencies are installed, including Express and the template library Jade:</p> + +<pre class="brush: js">{ + "name": "helloworld", + "version": "0.0.0", + "private": true, + "scripts": { + "start": "node ./bin/www" + }, + "dependencies": { + "cookie-parser": "~1.4.3", + "debug": "~2.6.9", + "express": "~4.16.0", + "http-errors": "~1.6.2", + "jade": "~1.11.0", + "morgan": "~1.9.0" + } +} +</pre> + +<p> </p> +</div> + +<p>Install all the dependencies for the helloworld app using NPM as shown:</p> + +<pre class="brush: bash">cd helloworld +npm install +</pre> + +<p>Then run the app (the commands are slightly different for Windows and Linux/macOS), as shown below:</p> + +<pre class="brush: bash"># Run the helloworld on Windows with Command Prompt +SET DEBUG=helloworld:* & npm start + +# Run the helloworld on Windows with PowerShell +SET DEBUG=helloworld:* | npm start + +# Run helloworld on Linux/macOS +DEBUG=helloworld:* npm start +</pre> + +<p>The DEBUG command creates useful logging, resulting in an output like that shown below.</p> + +<pre class="brush: bash">>SET DEBUG=helloworld:* & npm start + +> helloworld@0.0.0 start D:\Github\expresstests\helloworld +> node ./bin/www + + helloworld:server Listening on port 3000 +0ms</pre> + +<p>Open a browser and navigate to <a href="http://127.0.0.1:3000/">http://127.0.0.1:3000/</a> to see the default Express welcome page.</p> + +<p><img alt="Express - Generated App Default Screen" src="https://mdn.mozillademos.org/files/14331/express_default_screen.png" style="border-style: solid; border-width: 1px; display: block; height: 301px; margin: 0px auto; width: 675px;"></p> + +<p>We'll talk more about the generated app when we get to the article on generating a skeleton application.</p> + +<ul> +</ul> + +<h2 id="Summary">Summary</h2> + +<p>You now have a Node development environment up and running on your computer that can be used for creating Express web applications. You've also seen how NPM can be used to import Express into an application, and also how you can create applications using the Express Application Generator tool and then run them.</p> + +<p>In the next article we start working through a tutorial to build a complete web application using this environment and associated tools.</p> + +<h2 id="See_also">See also</h2> + +<ul> + <li><a href="https://nodejs.org/en/download/">Downloads</a> page (nodejs.org)</li> + <li><a href="https://nodejs.org/en/download/package-manager/">Installing Node.js via package manager</a> (nodejs.org)</li> + <li><a href="http://expressjs.com/en/starter/installing.html">Installing Express</a> (expressjs.com)</li> + <li><a href="https://expressjs.com/en/starter/generator.html">Express Application Generator</a> (expressjs.com)</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/Introduction", "Learn/Server-side/Express_Nodejs/Tutorial_local_library_website", "Learn/Server-side/Express_Nodejs")}}</p> + +<p> </p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction">Express/Node introduction</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/development_environment">Setting up a Node (Express) development environment</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">Express Tutorial: The Local Library website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website">Express Tutorial Part 2: Creating a skeleton website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/mongoose">Express Tutorial Part 3: Using a Database (with Mongoose)</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/routes">Express Tutorial Part 4: Routes and controllers</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express Tutorial Part 5: Displaying library data</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms">Express Tutorial Part 6: Working with forms</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/deployment">Express Tutorial Part 7: Deploying to production</a></li> +</ul> + +<p> </p> diff --git a/files/ko/learn/server-side/express_nodejs/스켈레톤_웹사이트/index.html b/files/ko/learn/server-side/express_nodejs/스켈레톤_웹사이트/index.html new file mode 100644 index 0000000000..ca72e39124 --- /dev/null +++ b/files/ko/learn/server-side/express_nodejs/스켈레톤_웹사이트/index.html @@ -0,0 +1,512 @@ +--- +title: 'Express Tutorial Part 2: 스켈레톤 웹사이트 만들기' +slug: Learn/Server-side/Express_Nodejs/스켈레톤_웹사이트 +translation_of: Learn/Server-side/Express_Nodejs/skeleton_website +--- +<div>{{LearnSidebar}}</div> + +<p>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/Tutorial_local_library_website", "Learn/Server-side/Express_Nodejs/mongoose", "Learn/Server-side/Express_Nodejs")}}</p> + +<p class="summary">This second article in our <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">Express Tutorial</a> shows how you can create a "skeleton" website project which you can then go on to populate with site-specific routes, templates/views, and database calls.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Prerequisites:</th> + <td><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/development_environment">Set up a Node development environment</a>. Review the Express Tutorial.</td> + </tr> + <tr> + <th scope="row">Objective:</th> + <td><em>Express 앱 제너레이터를 사용하여 자신만의 새로운 웹사이트 프로젝트를 시작할 수 있다.</em></td> + </tr> + </tbody> +</table> + +<h2 id="Overview">Overview</h2> + +<p>이 아티클은 당신이 <a href="https://expressjs.com/en/starter/generator.html">Express Application Generator</a> 도구를 이용하여 스켈레톤(최소한의 프레임 모형만 갖춘) 웹사이트를 만드는 방법을 보여줍니다. 이는 사이트에 맞춘 라우트, 뷰/템플릿 그리고 데이터 베이스를 사용할 수 있게 합니다. In this case, we'll use the tool to create the framework for our <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">Local Library website</a>, to which we'll later add all the other code needed by the site. The process is extremely simple, requiring only that you invoke the generator on the command line with a new project name, optionally also specifying the site's template engine and CSS generator.</p> + +<p><span style="line-height: 1.5;">The following sections show you how to call the application generator, and provides a little explanation about the different view/CSS options. We'll also explain how the skeleton website is structured. At the end, we'll show how you can run the website to verify that it works.</span></p> + +<div class="note"> +<p><span style="line-height: 1.5;"><strong>Note</strong>: The <em>Express Application Generator</em> is not the only generator for Express applications, and the generated project is not the only viable way to structure your files and directories. The generated site does however have a modular structure that is easy to extend and understand. For information about a <em>minimal</em> Express application, see <a href="https://expressjs.com/en/starter/hello-world.html">Hello world example</a> (Express docs).</span></p> +</div> + +<h2 id="Using_the_application_generator">Using the application generator</h2> + +<p>You should already have installed the generator as part of <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/development_environment">setting up a Node development environment</a>. As a quick reminder, you install the generator tool site-wide using the NPM package manager, as shown:</p> + +<pre class="brush: bash"><code>npm install express-generator -g</code></pre> + +<p>The generator has a number of options, which you can view on the command line using the <code>--help</code> (or <code>-h</code>) command:</p> + +<pre class="brush: bash">> express --help + + Usage: express [options] [dir] + + + Options: + + --version output the version number + -e, --ejs add ejs engine support + --pug add pug engine support + --hbs add handlebars engine support + -H, --hogan add hogan.js engine support + -v, --view <engine> add view <engine> support (dust|ejs|hbs|hjs|jade|pug|twig|vash) (defaults to jade) + --no-view use static html instead of view engine + -c, --css <engine> add stylesheet <engine> support (less|stylus|compass|sass) (defaults to plain css) + --git add .gitignore + -f, --force force on non-empty directory + -h, --help output usage information +</pre> + +<p>You can simply specify <code>express</code> to create a project inside the <em>current</em> directory using the <em>Jade</em> view engine and plain CSS (if you specify a directory name then the project will be created in a sub-folder with that name).</p> + +<pre class="brush: bash"><code>express</code></pre> + +<p>You can also choose a view (template) engine using <code>--view</code> and/or a CSS generation engine using <code>--css</code>.</p> + +<div class="note"> +<p><strong>Note:</strong> The other options for choosing template engines (e.g. <code>--hogan</code>, <code>--ejs</code>, <code>--hbs</code> etc.) are deprecated. Use <code>--view</code> (or<code> -v</code>)!</p> +</div> + +<h3 id="What_view_engine_should_I_use">What view engine should I use?</h3> + +<p>The <em>Express Application Generator</em> allows you to configure a number of popular view/templating engines, including <a href="https://www.npmjs.com/package/ejs">EJS</a>, <a href="http://github.com/donpark/hbs">Hbs</a>, <a href="https://pugjs.org/api/getting-started.html">Pug</a> (Jade), <a href="https://www.npmjs.com/package/twig">Twig</a>, and <a href="https://www.npmjs.com/package/vash">Vash</a>, although it chooses Jade by default if you don't specify a view option. Express itself can also support a large number of other templating languages <a href="https://github.com/expressjs/express/wiki#template-engines">out of the box</a>.</p> + +<div class="note"> +<p><strong>Note:</strong> If you want to use a template engine that isn't supported by the generator then see <a href="https://expressjs.com/en/guide/using-template-engines.html">Using template engines with Express</a> (Express docs) and the documentation for your target view engine.</p> +</div> + +<p>Generally speaking, you should select a templating engine that delivers all the functionality you need and allows you to be productive sooner — or in other words, in the same way that you choose any other component! Some of the things to consider when comparing template engines:</p> + +<ul> + <li>Time to productivity — If your team already has experience with a templating language then it is likely they will be productive faster using that language. If not, then you should consider the relative learning curve for candidate templating engines.</li> + <li>Popularity and activity — Review the popularity of the engine and whether it has an active community. It is important to be able to get support for the engine when you have problems over the lifetime of the website.</li> + <li>Style — Some template engines use specific markup to indicate inserted content within "ordinary" HTML, while others construct the HTML using a different syntax (for example, using indentation and block names).</li> + <li>Performance/rendering time.</li> + <li>Features — you should consider whether the engines you look at have the following features available: + <ul> + <li>Layout inheritance: Allows you to define a base template and then "inherit" just the parts of it that you want to be different for a particular page. This is typically a better approach than building templates by including a number of required components or building a template from scratch each time.</li> + <li>"Include" support: Allows you to build up templates by including other templates.</li> + <li>Concise variable and loop control syntax.</li> + <li>Ability to filter variable values at template level (e.g. making variables upper-case, or formatting a date value).</li> + <li>Ability to generate output formats other than HTML (e.g. JSON or XML).</li> + <li>Support for asynchronous operations and streaming.</li> + <li>Can be used on the client as well as the server. If a templating engine can be used on the client this allows the possibility of serving data and having all or most of the rendering done client-side.</li> + </ul> + </li> +</ul> + +<div class="note"> +<p><strong>Tip:</strong> There are many resources on the Internet to help you compare the different options!</p> +</div> + +<p>For this project, we'll use the <a href="https://pugjs.org/api/getting-started.html">Pug</a> templating engine (this is the recently-renamed Jade engine), as this is one of the most popular Express/JavaScript templating languages and is supported out of the box by the generator.</p> + +<h3 id="What_CSS_stylesheet_engine_should_I_use">What CSS stylesheet engine should I use?</h3> + +<p>The <em>Express Application Generator</em> allows you to create a project that is configured to use the most common CSS stylesheet engines: <a href="http://lesscss.org/">LESS</a>, <a href="http://sass-lang.com/">SASS</a>, <a href="http://compass-style.org/">Compass</a>, <a href="http://stylus-lang.com/">Stylus</a>.</p> + +<div class="note"> +<p><strong>Note: </strong>CSS has some limitations that make certain tasks difficult. CSS stylesheet engines allow you to use more powerful syntax for defining your CSS and then compile the definition into plain-old CSS for browsers to use.</p> +</div> + +<p>As with templating engines, you should use the stylesheet engine that will allow your team to be most productive. For this project, we'll use the ordinary CSS (the default) as our CSS requirements are not sufficiently complicated to justify using anything else.</p> + +<h3 id="What_database_should_I_use">What database should I use?</h3> + +<p>The generated code doesn't use/include any databases. <em>Express</em> apps can use any <a href="https://expressjs.com/en/guide/database-integration.html">database mechanism</a> supported by <em>Node</em> (<em>Express</em> itself doesn't define any specific additional behavior/requirements for database management).</p> + +<p>We'll discuss how to integrate with a database in a later article.</p> + +<h2 id="Creating_the_project">Creating the project</h2> + +<p><em>Local Library</em> 샘플 앱을 위해서 우리는 <em>express-locallibrary-tutorial </em>라는 이름의 프로젝트를 생성할 것입니다. <em>Pug</em> 라는(jade의 후속격) 템플릿 라이브러리를 사용할 것이며, CSS stylesheet 엔진은 사용하지 않습니다.</p> + +<p>First, navigate to where you want to create the project and then run the <em>Express Application Generator</em> in the command prompt as shown:</p> + +<pre class="brush: bash">express express-locallibrary-tutorial --view=pug +</pre> + +<p>The generator will create (and list) the project's files.</p> + +<pre class="brush: bash"> create : express-locallibrary-tutorial\ + create : express-locallibrary-tutorial\public\ + create : express-locallibrary-tutorial\public\javascripts\ + create : express-locallibrary-tutorial\public\images\ + create : express-locallibrary-tutorial\public\stylesheets\ + create : express-locallibrary-tutorial\public\stylesheets\style.css + create : express-locallibrary-tutorial\routes\ + create : express-locallibrary-tutorial\routes\index.js + create : express-locallibrary-tutorial\routes\users.js + create : express-locallibrary-tutorial\views\ + create : express-locallibrary-tutorial\views\error.pug + create : express-locallibrary-tutorial\views\index.pug + create : express-locallibrary-tutorial\views\layout.pug + create : express-locallibrary-tutorial\app.js + create : express-locallibrary-tutorial\package.json + create : express-locallibrary-tutorial\bin\ + create : express-locallibrary-tutorial\bin\www + + change directory: + > cd express-locallibrary-tutorial + + install dependencies: + > npm install + + run the app: + > SET DEBUG=express-locallibrary-tutorial:* & npm start</pre> + +<p>At the end of the output, the generator provides instructions on how you install the dependencies (as listed in the <strong>package.json</strong> file) and then how to run the application (the instructions above are for Windows; on Linux/macOS they will be slightly different).</p> + +<div class="blockIndicator note"> +<p><strong>Note:</strong> When using Windows, the && and & assumes you are using the Command Prompt. If you are using the new default PowerShell terminal do not concatenate the commands with && and &. Instead set the DEBUG environment variable with $ENV:DEBUG = "express-locallibrary-tutorial:*";. The npm start can be followed by the npm start. </p> +</div> + +<h2 id="Running_the_skeleton_website">Running the skeleton website</h2> + +<p>At this point, we have a complete skeleton project. The website doesn't actually <em>do</em> very much yet, but it's worth running it to show how it works.</p> + +<ol> + <li>First, install the dependencies (the <code>install</code> command will fetch all the dependency packages listed in the project's<strong> package.json</strong> file). + + <pre class="brush: bash">cd express-locallibrary-tutorial +npm install</pre> + </li> + <li>Then run the application. + <ul> + <li>On Windows, use this command: + <pre class="brush: bash">SET DEBUG=express-locallibrary-tutorial:* & npm start</pre> + </li> + <li>On macOS or Linux, use this command: + <pre class="brush: bash">DEBUG=express-locallibrary-tutorial:* npm start +</pre> + </li> + </ul> + </li> + <li>Then load <a href="http://localhost:3000/">http://localhost:3000/</a> in your browser to access the app.</li> +</ol> + +<p>You should see a browser page that looks like this:</p> + +<p><img alt="Browser for default Express app generator website" src="https://mdn.mozillademos.org/files/14375/ExpressGeneratorSkeletonWebsite.png" style="display: block; height: 403px; margin: 0px auto; width: 576px;"></p> + +<p>You have a working Express application, serving itself to <em>localhost:3000</em>.</p> + +<div class="note"> +<p><strong>Note:</strong> You could also start the app just using the <code>npm start</code> command. Specifying the DEBUG variable as shown enables console logging/debugging. For example, when you visit the above page you'll see debug output like this:</p> + +<pre class="brush: bash">>SET DEBUG=express-locallibrary-tutorial:* & npm start + +> express-locallibrary-tutorial@0.0.0 start D:\github\mdn\test\exprgen\express-locallibrary-tutorial +> node ./bin/www + + express-locallibrary-tutorial:server Listening on port 3000 +0ms +GET / 304 490.296 ms - - +GET /stylesheets/style.css 200 4.886 ms - 111 +</pre> +</div> + +<h2 id="Enable_server_restart_on_file_changes">Enable server restart on file changes</h2> + +<p>Any changes you make to your Express website are currently not visible until you restart the server. It quickly becomes very irritating to have to stop and restart your server every time you make a change, so it is worth taking the time to automate restarting the server when needed.</p> + +<p>One of the easiest such tools for this purpose is <a href="https://github.com/remy/nodemon">nodemon</a>. This is usually installed globally (as it is a "tool"), but here we'll install and use it locally as a <em>developer dependency</em>, so that any developers working with the project get it automatically when they install the application. Use the following command in the root directory for the skeleton project:</p> + +<pre class="brush: bash">npm install --save-dev nodemon</pre> + +<p>If you still choose to install <a href="https://github.com/remy/nodemon">nodemon</a> globally to your machine, and not only to your project's <strong>package.json</strong> file:</p> + +<pre class="brush: bash">npm install -g nodemon</pre> + +<p>If you open your project's <strong>package.json</strong> file you'll now see a new section with this dependency:</p> + +<pre class="brush: json"> "devDependencies": { + "nodemon": "^1.18.10" +} +</pre> + +<p>Because the tool isn't installed globally we can't launch it from the command line (unless we add it to the path) but we can call it from an NPM script because NPM knows all about the installed packages. Find the the <code>scripts</code> section of your package.json. Initially, it will contain one line, which begins with <code>"start"</code>. Update it by putting a comma at the end of that line, and adding the <code>"devstart"</code> line seen below:</p> + +<pre class="brush: json"> "scripts": { + "start": "node ./bin/www"<strong>,</strong> +<strong> "devstart": "nodemon ./bin/www", + "serverstart": "</strong>DEBUG=express-locallibrary-tutorial:* npm <strong>run devstart"</strong> + }, +</pre> + +<p>We can now start the server in almost exactly the same way as previously, but with the <code>devstart</code> command specified:</p> + +<ul> + <li>On Windows, use this command: + <pre class="brush: bash">SET DEBUG=express-locallibrary-tutorial:* & npm <strong>run devstart</strong></pre> + </li> + <li>On macOS or Linux, use this command: + <pre class="brush: bash">DEBUG=express-locallibrary-tutorial:* npm <strong>run devstart</strong> +</pre> + </li> +</ul> + +<div class="note"> +<p><strong>Note:</strong> Now if you edit any file in the project the server will restart (or you can restart it by typing <code>rs</code> on the command prompt at any time). You will still need to reload the browser to refresh the page.</p> + +<p>We now have to call "<code>npm run <em><scriptname></em></code>" rather than just <code>npm start</code>, because "start" is actually an NPM command that is mapped to the named script. We could have replaced the command in the <em>start</em> script but we only want to use <em>nodemon</em> during development, so it makes sense to create a new script command.</p> + +<p>The <code>serverstart</code> command added to the scripts in the <strong>package.json</strong> above is a very good example. Using this approach means you no longer have to type a long command shown to start the server. Note that the particular command added to the script works for macOS or Linux only.</p> +</div> + +<h2 id="The_generated_project">The generated project</h2> + +<p>Let's now take a look at the project we just created.</p> + +<h3 id="Directory_structure">Directory structure</h3> + +<p>The generated project, now that you have installed dependencies, has the following file structure (files are the items <strong>not</strong> prefixed with "/"). The <strong>package.json</strong> file defines the application dependencies and other information. It also defines a startup script that will call the application entry point, the JavaScript file <strong>/bin/www</strong>. This sets up some of the application error handling and then loads <strong>app.js</strong> to do the rest of the work. The app routes are stored in separate modules under the <strong>routes/</strong> directory. The templates are stored under the /<strong>views</strong> directory.</p> + +<pre>/express-locallibrary-tutorial + <strong>app.js</strong> + /bin + <strong>www</strong> + <strong>package.json</strong> + <strong>package-lock.json</strong> + /node_modules + [about 6700 subdirectories and files] + /public + /images + /javascripts + /stylesheets + <strong>style.css</strong> + /routes + <strong>index.js</strong> + <strong>users.js</strong> + /views + <strong>error.pug</strong> + <strong>index.pug</strong> + <strong>layout.pug</strong> + +</pre> + +<p>The following sections describe the files in a little more detail.</p> + +<h3 id="package.json">package.json</h3> + +<p>The <strong>package.json </strong>file defines the application dependencies and other information:</p> + +<pre class="brush: json">{ + "name": "express-locallibrary-tutorial", + "version": "0.0.0", + "private": true, + "scripts": { + "start": "node ./bin/www", + "devstart": "nodemon ./bin/www" + }, + "dependencies": { + "cookie-parser": "~1.4.3", + "debug": "~2.6.9", + "express": "~4.16.0", + "http-errors": "~1.6.2", + "morgan": "~1.9.0", + "pug": "2.0.0-beta11" + }, + "devDependencies": { + "nodemon": "^1.18.10" + } +} +</pre> + +<p>The dependencies include the <em>express</em> package and the package for our selected view engine (<em>pug</em>). In addition, we have the following packages that are useful in many web applications:</p> + +<ul> + <li><a href="https://www.npmjs.com/package/cookie-parser">cookie-parser</a>: Used to parse the cookie header and populate <code>req.cookies</code> (essentially provides a convenient method for accessing cookie information).</li> + <li><a href="https://www.npmjs.com/package/debug">debug</a>: A tiny node debugging utility modeled after node core's debugging technique.</li> + <li><a href="https://www.npmjs.com/package/morgan">morgan</a>: An HTTP request logger middleware for node.</li> + <li><a href="https://www.npmjs.com/package/http-errors">http-errors</a>: Create HTTP errors where needed (for express error handling).</li> +</ul> + +<p>The scripts section defines a "<em>start</em>" script, which is what we are invoking when we call <code>npm start</code> to start the server. From the script definition, you can see that this actually starts the JavaScript file <strong>./bin/www</strong> with <em>node</em>. It also defines a "<em>devstart</em>" script, which we invoke when calling <code>npm run devstart</code> instead. This starts the same <strong>./bin/www</strong> file, but with <em>nodemon</em> rather than <em>node</em>.</p> + +<pre class="brush: json"> "scripts": { + "start": "node ./bin/www", + "devstart": "nodemon ./bin/www" + }, +</pre> + +<h3 id="www_file">www file</h3> + +<p>The file <strong>/bin/www</strong> is the application entry point! The very first thing this does is <code>require()</code> the "real" application entry point (<strong>app.js</strong>, in the project root) that sets up and returns the <code><a href="http://expressjs.com/en/api.html">express()</a></code> application object.</p> + +<pre class="brush: js">#!/usr/bin/env node + +/** + * Module dependencies. + */ + +<strong>var app = require('../app');</strong> +</pre> + +<div class="note"> +<p><strong>Note:</strong> <code>require()</code> is a global node function that is used to import modules into the current file. Here we specify <strong>app.js</strong> module using a relative path and omitting the optional (.<strong>js</strong>) file extension.</p> +</div> + +<p>The remainder of the code in this file sets up a node HTTP server with <code>app</code> set to a specific port (defined in an environment variable or 3000 if the variable isn't defined), and starts listening and reporting server errors and connections. For now you don't really need to know anything else about the code (everything in this file is "boilerplate"), but feel free to review it if you're interested.</p> + +<h3 id="app.js">app.js</h3> + +<p>This file creates an <code>express</code> application object (named <code>app</code>, by convention), sets up the application with various settings and middleware, and then exports the app from the module. The code below shows just the parts of the file that create and export the app object:</p> + +<pre class="brush: js"><code>var express = require('express'); +var app = express(); +... +</code>module.exports = app; +</pre> + +<p>Back in the <strong>www</strong> entry point file above, it is this <code>module.exports</code> object that is supplied to the caller when this file is imported.</p> + +<p>Let's work through the <strong>app.js</strong> file in detail. First, we import some useful node libraries into the file using <code>require()</code>, including http-errors, <em>express</em>, <em>morgan</em> and <em>cookie-parser</em> that we previously downloaded for our application using NPM; and <em>path</em>, which is a core Node library for parsing file and directory paths.</p> + +<pre class="brush: js">var createError = require('http-errors'); +var express = require('express'); +var path = require('path'); +var cookieParser = require('cookie-parser'); +var logger = require('morgan'); +</pre> + +<p>Then we <code>require()</code> modules from our routes directory. These modules/files contain code for handling particular sets of related "routes" (URL paths). When we extend the skeleton application, for example to list all books in the library, we will add a new file for dealing with book-related routes.</p> + +<pre class="brush: js">var indexRouter = require('./routes/index'); +var usersRouter = require('./routes/users'); +</pre> + +<div class="note"> +<p><strong>Note:</strong> At this point, we have just <em>imported</em> the module; we haven't actually used its routes yet (this happens just a little bit further down the file).</p> +</div> + +<p>Next, we create the <code>app</code> object using our imported <em>express</em> module, and then use it to set up the view (template) engine. There are two parts to setting up the engine. First, we set the '<code>views</code>' value to specify the folder where the templates will be stored (in this case the subfolder <strong>/views</strong>). Then we set the '<code>view engine</code>' value to specify the template library (in this case "pug").</p> + +<pre class="brush: js">var app = express(); + +// view engine setup +app.set('views', path.join(__dirname, 'views')); +app.set('view engine', 'pug'); +</pre> + +<p>The next set of functions call <code>app.use()</code> to add the <em>middleware</em> libraries into the request handling chain. In addition to the 3rd party libraries we imported previously, we use the <code>express.static</code> middleware to get <em>Express</em> to serve all the static files in the <strong>/public</strong> directory in the project root.</p> + +<pre class="brush: js">app.use(logger('dev')); +app.use(express.json()); +app.use(express.urlencoded({ extended: false })); +app.use(cookieParser()); +<strong>app.use(express.static(path.join(__dirname, 'public')));</strong> +</pre> + +<p>Now that all the other middleware is set up, we add our (previously imported) route-handling code to the request handling chain. The imported code will define particular routes for the different <em>parts</em> of the site:</p> + +<pre class="brush: js">app.use('/', indexRouter); +app.use('/users', usersRouter); +</pre> + +<div class="note"> +<p><strong>Note:</strong> The paths specified above ('/' and '<code>/users'</code>) are treated as a prefix to routes defined in the imported files. So for example, if the imported <strong>users</strong> module defines a route for <code>/profile</code>, you would access that route at <code>/users/profile</code>. We'll talk more about routes in a later article.</p> +</div> + +<p id="error_handling">The last middleware in the file adds handler methods for errors and HTTP 404 responses.</p> + +<pre class="brush: js">// catch 404 and forward to error handler +app.use(function(req, res, next) { + next(createError(404)); +}); + +// error handler +app.use(function(err, req, res, next) { + // set locals, only providing error in development + res.locals.message = err.message; + res.locals.error = req.app.get('env') === 'development' ? err : {}; + + // render the error page + res.status(err.status || 500); + res.render('error'); +}); +</pre> + +<p>The Express application object (app) is now fully configured. The last step is to add it to the module exports (this is what allows it to be imported by <strong>/bin/www</strong>).</p> + +<pre class="brush: js">module.exports = app;</pre> + +<h3 id="Routes">Routes</h3> + +<p>The route file <strong>/routes/users.js</strong> is shown below (route files share a similar structure, so we don't need to also show <strong>index.js</strong>). First, it loads the <em>express</em> module and uses it to get an <code>express.Router</code> object. Then it specifies a route on that object and lastly exports the router from the module (this is what allows the file to be imported into <strong>app.js</strong>).</p> + +<pre class="brush: js">var express = require('express'); +var router = express.Router(); + +/* GET users listing. */ +<strong>router.get('/', function(req, res, next) { + res.send('respond with a resource');</strong> +}); + +module.exports = router; +</pre> + +<p>The route defines a callback that will be invoked whenever an HTTP <code>GET</code> request with the correct pattern is detected. The matching pattern is the route specified when the module is imported ('<code>/users</code>') plus whatever is defined in this file ('<code>/</code>'). In other words, this route will be used when an URL of <code>/users/</code> is received.</p> + +<div class="note"> +<p><strong>Tip:</strong> Try this out by running the server with node and visiting the URL in your browser: <a href="http://localhost:3000/users/">http://localhost:3000/users/</a>. You should see a message: 'respond with a resource'.</p> +</div> + +<p>One thing of interest above is that the callback function has the third argument '<code>next</code>', and is hence a middleware function rather than a simple route callback. While the code doesn't currently use the <code>next</code> argument, it may be useful in the future if you want to add multiple route handlers to the <code>'/'</code> route path.</p> + +<h3 id="Views_templates">Views (templates)</h3> + +<p>The views (templates) are stored in the <strong>/views</strong> directory (as specified in <strong>app.js</strong>) and are given the file extension <strong>.pug</strong>. The method <code><a href="http://expressjs.com/en/4x/api.html#res.render">Response.render()</a></code> is used to render a specified template along with the values of named variables passed in an object, and then send the result as a response. In the code below from <strong>/routes/index.js</strong> you can see how that route renders a response using the template "index" passing the template variable "title".</p> + +<pre class="brush: js">/* GET home page. */ +router.get('/', function(req, res, next) { + res.render('index', { title: 'Express' }); +}); +</pre> + +<p>The corresponding template for the above route is given below (<strong>index.pug</strong>). We'll talk more about the syntax later. All you need to know for now is that the <code>title</code> variable (with value <code>'Express'</code>) is inserted where specified in the template.</p> + +<pre>extends layout + +block content + h1= title + p Welcome to #{title} +</pre> + +<h2 id="Challenge_yourself">Challenge yourself</h2> + +<p>Create a new route in <strong>/routes/users.js</strong> that will display the text "<em>You're so cool"</em> at URL <code>/users/cool/</code>. Test it by running the server and visiting <a href="http://localhost:3000/users/cool/">http://localhost:3000/users/cool/</a> in your browser</p> + +<ul> +</ul> + +<h2 id="Summary">Summary</h2> + +<p>You have now created a skeleton website project for the <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">Local Library</a> and verified that it runs using <em>node</em>. Most importantly, you also understand how the project is structured, so you have a good idea where we need to make changes to add routes and views for our local library.</p> + +<p>Next, we'll start modifying the skeleton so that it works as a library website.</p> + +<h2 id="See_also">See also</h2> + +<ul> + <li><a href="https://expressjs.com/en/starter/generator.html">Express application generator</a> (Express docs)</li> + <li><a href="https://expressjs.com/en/guide/using-template-engines.html">Using template engines with Express</a> (Express docs)</li> +</ul> + +<p>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/Tutorial_local_library_website", "Learn/Server-side/Express_Nodejs/mongoose", "Learn/Server-side/Express_Nodejs")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction">Express/Node introduction</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/development_environment">Setting up a Node (Express) development environment</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">Express Tutorial: The Local Library website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website">Express Tutorial Part 2: Creating a skeleton website</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/mongoose">Express Tutorial Part 3: Using a Database (with Mongoose)</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/routes">Express Tutorial Part 4: Routes and controllers</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express Tutorial Part 5: Displaying library data</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms">Express Tutorial Part 6: Working with forms</a></li> + <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/deployment">Express Tutorial Part 7: Deploying to production</a></li> +</ul> diff --git a/files/ko/learn/server-side/first_steps/client-server_overview/index.html b/files/ko/learn/server-side/first_steps/client-server_overview/index.html new file mode 100644 index 0000000000..cc39e1802e --- /dev/null +++ b/files/ko/learn/server-side/first_steps/client-server_overview/index.html @@ -0,0 +1,324 @@ +--- +title: Client-Server overview +slug: Learn/Server-side/First_steps/Client-Server_overview +tags: + - 서버측 프로그래밍 +translation_of: Learn/Server-side/First_steps/Client-Server_overview +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/First_steps/Introduction", "Learn/Server-side/First_steps/Web_frameworks", "Learn/Server-side/First_steps")}}</div> + +<p class="summary">이제 서버 측 프로그래밍의 목적과 잠재적 이점을 알았으니 서버가 브라우저에서 "동적 요청"을받을 때 어떤 일이 발생하는지 자세히 살펴 보겠습니다. 대부분의 웹 사이트 서버 측 코드는 요청 및 응답을 비슷한 방식으로 처리하므로 대부분의 코드를 작성할 때 수행해야 할 작업을 이해하는 데 도움이됩니다</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">선수 과목:</th> + <td> + <p>기본적인 컴퓨터 활용법,</p> + + <p>웹서버에 대한 기초적인 이해</p> + </td> + </tr> + <tr> + <th scope="row">목적:</th> + <td> + <p>클라이언트-서버가 동적 웹사이트에서 어떻게 상호작용을 하는지 이해하고, </p> + + <p>특히 서버 측 코드로 수행해야하는 작업을 이해합니다.</p> + </td> + </tr> + </tbody> +</table> + +<p>이 기사는 실제 코드가 없습니다. 왜냐하면 우리는 아직 어떤 웹프레임 워크를 사용하여 코드를 작성할지 선택하지 않았기 때문입니다. 그러나 설명된 동작은 사용자가 선택하는 언어나 웹 프레임워크와 관계없이 서버 측 코드에 의해 구현 되야하므로 이 기사는 여전히 관계가 있습니다.</p> + +<h2 id="Web_servers_and_HTTP_(a_primer)">Web servers and HTTP (a primer)</h2> + +<p>웹 브라우저는 <strong>H</strong>yper<strong>T</strong>ext <strong>T</strong>ransport <strong>P</strong>rotocol (<a href="https://developer.mozilla.org/ko/docs/Web/HTTP">HTTP</a>)을 사용 하여 웹 서버와 통신을 합니다 . 당신이 웹 페이지의 링크를 클릭하거나, form을 전송 하거나, 검색을 시작하거나 할 때 웹 브라우저는 <em>HTTP Request</em>를 서버에 보냅니다.</p> + +<p>이 요청이 포함 하는것은 다음과 같습니다:</p> + +<ul> + <li>대상 서버및 리소스를 식별하는 URL. (예: HTML파일, 서버의 특별한 데이터 요소, 또는 실행할 도구)</li> + <li>필요한 행동을 정의할 메소드 (예를 들면, 파일을 얻거나 어떤 데이터를 저장하거나 업데이트하는 것). 여러 메소드/단어 그리고 그들과 관련된 행동이 아래에 나열 되어있습니다: + <ul> + <li><code>GET</code>: 특정 리소스를 얻습니다. (예: 제품의 대한 정보 또는 제품 목록을 제공하는 HTML파일). </li> + <li><code>POST</code>: 새로운 리소스를 만듭니다. (예: 위키에 새로운 기사를 추가 하기, 데이터베이스와 새로운 연결을 추가하기). </li> + <li><code>HEAD</code>: 특정 리소스의 내용 부분을 제외한 메타데이터 정보를 가져옵니다. 예를 들어 HEAD 요청을 사용하여 리소스가 마지막으로 업데이트 된 시간을 확인한 다음 리소스가 변경된 경우에만 (더 비싼) GET 요청을 사용하여 리소스를 다운로드 할 수 있습니다. </li> + <li><code>PUT</code>: 기존에 있던 리소스를 업데이트 합니다. (또는 그 리소스가 없었다면 새로 만들어줍니다)</li> + <li><code>DELETE</code>: 특정 리소스를 삭제합니다.</li> + <li><code>TRACE</code>, <code>OPTIONS</code>, <code>CONNECT</code>, <code>PATCH</code>: 이 메소드는 덜 일반적인 / 고급 작업을위한 것이므로 여기서 다루지는 않습니다.</li> + </ul> + </li> + <li>요청과 함께 추가 정보 (예 : HTML 양식 데이터)를 인코딩 할 수 있습니다. 정보는 다음과 같이 인코딩 될 수 있습니다:</li> +</ul> + +<p>URL 매개변수들: <code>GET</code> requests는 이름/값 쌍을 끝에 추가하여 서버에 보낸 URL 데이터를 인코딩 합니다. 예를 들어<code>http://mysite.com<strong>?name=Fred&age=11</strong></code>. 물음표(<code>?</code>)를 항상 볼수 있는데 이것은 URL과 URL 매개변수를 분리 합니다, (<code>=</code>)은 매개변수의 이름과 값을 분리합니다. 그리고(<code>&</code>)는 이름/값 쌍을 분리합니다. URL 매개 변수는 사용자가 변경하여 다시 제출할 수 있으므로 본질적으로 "안전하지 않음"입니다. 그런 이유로URL 매개변수들/<code>GET</code> 요청은 서버에 데이터를 업데이트를 하는 요청에 사용되지 않습니다.</p> + +<ul> + <li><code>POST</code> 데이터. POST 요청은 요청 본문 내에 인코딩 된 데이터를 새 리소스에 추가합니다.</li> + <li>클라이언트 측 쿠키. 쿠키는 서버가 로그인 상태 및 권한 / 자원에 대한 액세스를 결정하는 데 사용할 수있는 키를 포함하여 클라이언트에 대한 세션 데이터를 포함합니다.</li> +</ul> + +<p>웹 서버는 클라이언트의 요청 메시지를 기다리고, 메시지가 오면 그것들을 처리하고, 웹 브라우저에 HTTP Response메시지를 응답합니다. 응답에는 요청 성공여부를 나타내는 <a href="https://developer.mozilla.org/ko/docs/Web/HTTP/Status">HTTP Response status code</a>를 포함합니다.(예 "<code>200 OK</code>" 응답 성공, "<code>404 Not Found</code>" 해당 리소스를 찾을 수 없음, "<code>403 Forbidden</code>" 사용자가 해당 리소스를 볼 자격을 증명하지 않음, 기타 등등). 성공적인 응답이라면 GET request에서 요청한 리소스를 포함한 본문 일 것 입니다.</p> + +<p>HTML 페이지가 반환 되면 웹 브라우저에 의해 렌더링 될 것입니다. 그 과정에서 브라우저는 다른 리소스와 링크된 것들을 찾을수도 있습니다.(예 HTML page 종종 JavaScript나 CSS pages를 참조합니다), 그리고 별도의 HTTP Requests로 그 파일들을 다운로드 합니다.</p> + +<p>정적 웹사이트및 동적 웹사이트는 (다음 섹션에서 설명하는) 정확히 같은 통신 프로토콜/패턴을 사용합니다.</p> + +<h3 id="GET_requestresponse_example">GET request/response example</h3> + +<p>당신은 링크를 클릭하거나 사이트를 검색하는 간단한 <code>GET</code> request를 만들 수 있습니다.(검색엔진의 홈페이지 같은). 예를 들자면, 만약 당신이 MDN에서 "클라이언트 서버 개요"를 검색하면 전송되는 HTTP request는 아래의 텍스트와 매우 유사할 것 입니다(메시지의 일부가 브라우저/설정에 따라 다르므로 같지는 않습니다).</p> + +<div class="note"> +<p>HTTP 메시지의 형식은 "웹 표준" (<a href="http://www.rfc-editor.org/rfc/rfc7230.txt">RFC7230</a>)에 정의 되어 있습니다. 이 수준의 세부사항을 알 필요는 없지만 적어도 이제는 이 모든 것이 어디서 왔는지를 알 수 있습니다!</p> +</div> + +<h4 id="The_request">The request</h4> + +<p>각 라인의 요청들은 그것이 어떤 정보인지 포함 하고 있습니다. 이러한 첫 부분을 <strong>header</strong>라고 합니다, <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML">HTML head</a>가 HTML 문서의 유용한 정보를 포함하는 것과 같은 방식으로 유용한 정보를 포함합니다. (실제로 본문에 있는 콘텐츠 자체는 아닙니다.):</p> + +<pre>GET https://developer.mozilla.org/en-US/search?q=client+server+overview&topic=apps&topic=html&topic=css&topic=js&topic=api&topic=webdev HTTP/1.1 +Host: developer.mozilla.org +Connection: keep-alive +Pragma: no-cache +Cache-Control: no-cache +Upgrade-Insecure-Requests: 1 +User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 +Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 +Referer: https://developer.mozilla.org/en-US/ +Accept-Encoding: gzip, deflate, sdch, br +<code>Accept-Charset: ISO-8859-1,UTF-8;q=0.7,*;q=0.7</code> +Accept-Language: en-US,en;q=0.8,es;q=0.6 +Cookie: sessionid=6ynxs23n521lu21b1t136rhbv7ezngie; csrftoken=zIPUJsAZv6pcgCBJSCj1zU6pQZbfMUAT; dwf_section_edit=False; dwf_sg_task_completion=False; _gat=1; _ga=GA1.2.1688886003.1471911953; ffo=true +</pre> + +<p>첫번째와 두번째라인은 위에서 우리가 말한 많은 종류의 정보를 포함 하고 있습니다:</p> + +<ul> + <li>요청의 타입(<code>GET</code>).</li> + <li>대상 리소스 URL (<code>/en-US/search</code>).</li> + <li>URL 인자들 (<code>q=client%2Bserver%2Boverview&topic=apps&topic=html&topic=css&topic=js&topic=api&topic=webdev</code>).</li> + <li>대상/호스트 웹 사이트 (developer.mozilla.org).</li> + <li>첫번째 줄의 끝 부분은 특정 프로토콜 버전을 식별하는 짧은 문자열도 포함 합니다 (<code>HTTP/1.1</code>).</li> +</ul> + +<p>마지막 줄은 서버측 쿠키의 대한 정보를 포함합니다. — 이번 케이스는 쿠키가 세션을 관리하는 id를 포함하는 것을 볼 수 있습니다. (<code>Cookie: sessionid=6ynxs23n521lu21b1t136rhbv7ezngie; ...</code>).</p> + +<p>나머지 줄은 사용하는 브라우저의 정보와 다룰수 있는 요청의 정렬한 정보들을 포함 하고 있습니다. 이것들을 예로 볼 수 있습니다:</p> + +<ul> + <li>나의 브라우저는 (<code>User-Agent</code>) Mozilla Firefox입니다(<code>Mozilla/5.0</code>).</li> + <li>gzip 의 압축된 정보들을 받아들일 수 있습니다(<code>Accept-Encoding: gzip</code>).</li> + <li>지정된 문자집합(<code>Accept-Charset: ISO-8859-1,UTF-8;q=0.7,*;q=0.7</code>) 과 언어들을 받아 들일 수 있습니다(<code>Accept-Language: de,en;q=0.7,en-us;q=0.3</code>).</li> + <li><code>Referer</code> 줄은 리소스가 링크된 웹 페이지를 포함하는 주소를 지시하고 있습니다 (i.e. the origin of the request, <code>https://developer.mozilla.org/en-US/</code>).</li> +</ul> + +<p>HTTP requests는 본문을 가질수 있지만 이번 케이스에서는 비어 있습니다.</p> + +<h4 id="The_response">The response</h4> + +<p>이 요청의 대한 응답의 첫번째 부분은 밑에서 볼 수 있습니다. header에는 다음과 같이 정보들을 포함 하고 있습니다:</p> + +<ul> + <li>응답 코드의 첫번째 줄은 <code>200 OK</code>를 포함 하고 있습니다, 이것은 우리에게 응답이 성공하였다는 것을 말해주고 있습니다.</li> + <li>응답 포맷은 <code>text/html</code>이라는 것을 볼 수 있습니다. (<code>Content-Type</code>).</li> + <li>또한 문자집합을 UTF-8로 사용하는 것을 볼 수 있습니다(<code>Content-Type: text/html; charset=utf-8</code>).</li> + <li>또한 이 header는 body가 얼마나 큰지 알려주고 있습니다. (<code>Content-Length: 41823</code>).</li> +</ul> + +<p>메시지의 마지막에는 요청에 의해 반환된 실제 HTML을 포함하는 <strong>본문 </strong>콘텐츠를 볼 수 있습니다.</p> + +<pre class="brush: html">HTTP/1.1 200 OK +Server: Apache +X-Backend-Server: developer1.webapp.scl3.mozilla.com +Vary: Accept,Cookie, Accept-Encoding +Content-Type: text/html; charset=utf-8 +Date: Wed, 07 Sep 2016 00:11:31 GMT +Keep-Alive: timeout=5, max=999 +Connection: Keep-Alive +X-Frame-Options: DENY +Allow: GET +X-Cache-Info: caching +Content-Length: 41823 + + + +<!DOCTYPE html> +<html lang="en-US" dir="ltr" class="redesign no-js" data-ffo-opensanslight=false data-ffo-opensans=false > +<head prefix="og: http://ogp.me/ns#"> + <meta charset="utf-8"> + <meta http-equiv="X-UA-Compatible" content="IE=Edge"> + <script>(function(d) { d.className = d.className.replace(/\bno-js/, ''); })(document.documentElement);</script> + ... +</pre> + +<p>응답 header의 나머지 부분은 응답(예. 생성 되었을 때), 서버및 브라우저가 처리하는 방법의 대한 정보를 포함하고 있습니다(예. <code>X-Frame-Options: DENY</code>행은 브라우저가 페이지를 다른 사이트의 {{htmlelement ( "iframe")}}에 삽입하는 것을 허용하지 않는 것을 지시합니다).</p> + +<h3 id="POST_requestresponse_example">POST request/response example</h3> + +<p>HTTP <code>POST</code>는 당신이 정보를 포함한 폼을 작성하여 서버에 저장하기 위해 전송할때 만들어집니다.</p> + +<h4 id="The_request_2">The request</h4> + +<p>아래의 텍스트는 사용자가 새로운 프로필 정보를 사이트에 전송할때 만들어지는 HTTP request를 보여줍니다. 이 요청의 대한 포맷은 이전 <code>GET</code> request의 예시와 거의 비슷해 보입니다, 그렇지만 첫번째 줄은 이것이 <code>POST</code> 요청임을 보여주고 있습니다. </p> + +<pre class="brush: html">POST https://developer.mozilla.org/en-US/profiles/hamishwillee/edit HTTP/1.1 +Host: developer.mozilla.org +Connection: keep-alive +Content-Length: 432 +Pragma: no-cache +Cache-Control: no-cache +Origin: https://developer.mozilla.org +Upgrade-Insecure-Requests: 1 +User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 +Content-Type: application/x-www-form-urlencoded +Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 +Referer: https://developer.mozilla.org/en-US/profiles/hamishwillee/edit +Accept-Encoding: gzip, deflate, br +Accept-Language: en-US,en;q=0.8,es;q=0.6 +Cookie: sessionid=6ynxs23n521lu21b1t136rhbv7ezngie; _gat=1; csrftoken=zIPUJsAZv6pcgCBJSCj1zU6pQZbfMUAT; dwf_section_edit=False; dwf_sg_task_completion=False; _ga=GA1.2.1688886003.1471911953; ffo=true + +csrfmiddlewaretoken=zIPUJsAZv6pcgCBJSCj1zU6pQZbfMUAT&user-username=hamishwillee&user-fullname=Hamish+Willee&user-title=&user-organization=&user-location=Australia&user-locale=en-US&user-timezone=Australia%2FMelbourne&user-irc_nickname=&user-interests=&user-expertise=&user-twitter_url=&user-stackoverflow_url=&user-linkedin_url=&user-mozillians_url=&user-facebook_url=</pre> + +<p>가장 큰 차이점은 URL이 인자를 가지고 있지 않다는 겁니다. 보다시피, 폼에서 온 정보들은 요청 본문에 인코딩 되어있습니다(예를 들면, 새 사용자의 전체 이름은 다음을 사용하여 설정 합니다: <code>&user-fullname=Hamish+Willee</code>).</p> + +<h4 id="The_response_2">The response</h4> + +<p>요청에서 온 응답은 아래와 같이 보여집니다. "<code>302 Found</code>"의 상태 코드는 브라우저에게 post가 성공했고, <code>Location</code> 필드가 지정된 페이지를 로드하기 위해 두번째 HTTP request를 실행해야 하는 것을 알려줍니다. 그렇지 않은 경우 정보는 <code>GET</code> request에 대한 응답정보와 유사합니다.</p> + +<pre class="brush: html">HTTP/1.1 302 FOUND +Server: Apache +X-Backend-Server: developer3.webapp.scl3.mozilla.com +Vary: Cookie +Vary: Accept-Encoding +Content-Type: text/html; charset=utf-8 +Date: Wed, 07 Sep 2016 00:38:13 GMT +Location: https://developer.mozilla.org/en-US/profiles/hamishwillee +Keep-Alive: timeout=5, max=1000 +Connection: Keep-Alive +X-Frame-Options: DENY +X-Cache-Info: not cacheable; request wasn't a GET or HEAD +Content-Length: 0 +</pre> + +<div class="note"> +<p><strong>Note</strong>: HTTP responses 그리고 requests를 보여주는 예시들은 <a href="https://www.telerik.com/download/fiddler">Fiddler </a>어플리케이션을 사용하여 캡처하였습니다, 그렇지만 당신은 스니퍼(e.g. <a href="http://web-sniffer.net/">http://web-sniffer.net/</a>)나 브라우저 확장 기능인 <a href="https://addons.mozilla.org/en-US/firefox/addon/httpfox/">HttpFox </a>같은 것을 사용하여 확인 할 수 있습니다. 이러한 것을 직접 시도해보세요. 링크된 도구들을 사용하여 여러 사이트들을 돌아다니고 프로필 정보를 수정 하여 다양한 requests 와 responses를 확인해보세요. 현대의 대부분 브라우저는 네트워크 요청을 모니터 할수 있는 도구 또한 가지고 있습니다 (예를들면, Firefox가 가진 도구인 <a href="/en-US/docs/Tools/Network_Monitor">Network Monitor</a> ).</p> +</div> + +<h2 id="Static_sites">Static sites</h2> + +<p>정적 사이트는 특정 리소스가 요청될 때마다 서버에서 하드 코딩된 동일한 컨텐츠를 반환하는 사이트 입니다. 예를 들면 당신이 <code>/static/myproduct1.html</code> 에서 제품에 대한 정보페이지를 가지고 있다면 , 이 페이지는 어떤 유저에게나 동일하게 반환될 것입니다. 만약 당신이 비슷한 제품을 사이트에 추가 하고 싶다면 당신은 다른 페이지를 추가하여야 합니다(예. <code>myproduct2.html</code>) . 이것은 실제로 비효율적이 될것입니다 — 제품 페이지가 수천이 된다면? 각 페이지에 (기본 페이지 템플릿, 구조체 등)걸쳐 많은 코드를 반복하고 페이지에 대한 구조를 변경하려는 경우 — 예를 들어 새로운 관련제품에 대한 섹션을 추가하는 경우 — 모든 페이지를 개별적으로 변경해야 합니다.</p> + +<div class="note"> +<p><strong>Note</strong>: 정적사이트는 작은수의 페이지만 가지고 있거나 같은 콘텐츠를 모든 유저에게 보내고 싶을때는 좋을 수 있습니다. 그렇지만 페이지 수가 많아지기 시작하면 상당한 비용의 유지비가 필요합니다.</p> +</div> + +<p>어떻게 작동하는지 다시 살펴보겠습니다, 마지막 기사에서 살펴본 정적 사이트의 아키텍쳐는다이어그램을 다시 살펴보면</p> + +<p><img alt="A simplified diagram of a static web server." src="https://mdn.mozillademos.org/files/13841/Basic%20Static%20App%20Server.png"></p> + +<p>유저가 페이지를 탐색하기를 원할 때, 브라우저는 지정된 HTML 페이지의 URL에 HTTP <code>GET</code> request를 보냅니다. 서버는 요청한 문서를 파일 시스템에서 탐색하고 문서와<a href="https://developer.mozilla.org/ko/docs/Web/HTTP/Status"> HTTP Response status code </a>"<code>200 OK</code>" (성공을 알려주는)를 포함하는 HTTP응답을 반환합니다. 만약 서버가 다른 상태 코드를 반환한다면, 예를들면 "<code>404 Not Found</code>"는 파일이 서버에 없는 경우이고 "<code>301 Moved Permanently</code>"는 파일은 존재하지만 다른 위치로 리다이렉트된 경우입니다 .</p> + +<p>이 정적 사이트는 오직 GET requests만 필요합니다, 왜냐하면 이 서버는 변경 할 수 있는 데이터는 저장하지 않기 때문입니다. 또한 HTTP Request 데이터에 기반한 응답을 바꿀 필요가 없습니다(예. URL 인자들 또는 쿠키). </p> + +<p>서버측 프로그래밍을 할때는 정적사이트가 어떻게 동작하는지 이해하는 것이 여전히 유용합니다, 왜냐하면 동적사이트가 정적 파일(CSS, JavaScript, static images, etc.)에 대한 요청을 다루는 방법이 거의 동일하기 때문입니다.</p> + +<h2 id="Dynamic_sites">Dynamic sites</h2> + +<p>동적 사이트는 특별한 URL과 데이터 요청에 의해 생성되거나 콘텐츠를 반환할 수 있습니다(특정 URL에 대해 항상 동일한 하드 코딩 된 파일을 반환하는 것이 아닙니다). 제품 사이트를 이용하는 예를 들면, 서버는 각 제품에 대한 HTML파일을 만들기보다 제품 "데이터"를 데이터베이스에 저장할 것입니다. 제품에 대한HTTP <code>GET</code> Request를 받으면, 서버는 제품ID를 결정하고, 데이터베이스에서 데이터를 가져오고, HTML 템플릿에 가져온 데이터를 집어넣은 HTML페이지를 생성할 것입니다. 이것은 정적 사이트보다 주요한 장점이 있습니다:</p> + +<p>데이터베이스를 통해 제품 정보를 쉽게 확장하거나 수정하거나 검색가능한 방식으로 효율적으로 저장 할 수있습니다.</p> + +<p>HTML 템플릿을 통해 HTML 구조를 매우 쉽게 바꿀 수 있도록 만들 수 있습니다, 왜냐하면 하나의 위치에 하나의 템플릿만 수행되어야하며 잠재적인 수천개의 정적 페이지에서 수행되지 않아야 하기 때문입니다.</p> + +<h3 id="Anatomy_of_a_dynamic_request">Anatomy of a dynamic request</h3> + +<p>이 섹션은 "동적" HTTP request와 response 사이클에 대한 단계별 개요를 제공하고, 마지막 기사에서 살펴본 내용을 훨씬 더 자세하게 소개합니다. "실제 상황을 유지하기 위해"우리는 코치가 HTML 형식으로 팀 이름과 팀 크기를 선택하고 다음 게임을 위해 제안 된 "최고의 라인업"을 얻을 수있는 스포츠 팀 매니저 웹 사이트의 컨텍스트를 사용합니다.</p> + +<p>아래 다이어그램은 "팀 코치"웹 사이트의 주요 요소와 코치가 "최고의 팀"목록에 액세스 할 때 일련의 작업 순서에 대한 번호가 매겨진 레이블을 보여줍니다. <em>사이트를 동적으로 만드는 부분들은</em> 웹 애플리케이션(이것은 HTTP 요청을 처리하고 HTTP 응답을 반환하는 서버 측 코드를 참조하는 방법입니다), 선수의 정보나 팀 코치의 정보를 포함한 데이터베이스 그리고 <em>HTML 템플릿입니다</em>.</p> + +<p><img alt="This is a diagram of a simple web server with step numbers for each of step of the client-server interaction." src="https://mdn.mozillademos.org/files/13829/Web%20Application%20with%20HTML%20and%20Steps.png" style="height: 584px; width: 1226px;"></p> + +<p>코치가 팀 이름과 플레이어의 수를 포함한 폼을 전송하면 작업 시퀀스는 다음과 같습니다:</p> + +<ol> + <li>웹 브라우저는 리소스에 대한 기본 URL을 사용하여 서버에 HTTP <code>GET</code> request을 생성합니다 (<code>/best</code>) , 그리고 팀 및 플레이어의 수를 URL인자로 인코딩하거나(예. <code>/best?team=my_team_name&show=11)또는 URL패턴</code> (예. <code>/best/my_team_name/11/</code>) 으로 인코딩 합니다. 이 요청은 데이터를 꺼내오는데에만 사용 하므로(데이터가 수정 되지 않음) GET request를 사용합니다. </li> + <li>웹 서버는 이 요청이 "동적"임을 감지하고 처리를 위해 웹 어플리케이션에 전달합니다(웹서버는 정의된 설정에 의한 패턴 매칭 방법에 기반한 다양한 URL들을 처리하는 방법을 결정 합니다).</li> + <li>웹 애플리케션은 이 요청의 대한 의도가 URL에 기반한 "최고의 팀 목록"을 얻는 것 인지 확인하고 (<code>/best/</code>) URL에서 필요한 팀 이름과 플레이어의 숫자를 찾아냅니다. 웹 어플리케이션은 데이터베이스를 통해 필요한 정보를 가져옵니다 (추가 "내부의" 인자들을 사용하여 어떤 플레이어가 "최고"인지 정의하고, 또한 클라이언트측 쿠키에서 로그인한 코치의 신분을 확인 할 수 있습니다).</li> + <li>웹 어플리케이션은 HTML template의 자리 표시 자에 데이터(데이터베이스를 통해)를 넣은 HTML 페이지를 동적으로 생성 합니다.</li> + <li>웹 어플리케이션은 생성된 HTML을 (웹 서버를 경유하여) 브라우저에 HTTP 상태코드 200 ("success")와 함께 반환합니다. 만약 어떤 것이 HTML을 반환 하는 것을 막았다면 웹 어플리케이션은 다른 코드를 반환할 것 입니다 —예를들자면 "404"는 팀이 존재 하지 않음을 지시합니다.</li> + <li>웹 브라우저가 반환한 HTML을 처리하고 참조하는 다른 CSS파일이나 Javascript 파일을 얻기위해 별도의 요청을 보냅니다(7단계를 보십시오).</li> + <li>웹 사이트는 파일 시스템에 있는 정적 파일을 로드하고 즉시 브라우저에 반환합니다(올바른 파일 처리는 설정 방법과 URL패턴 매칭을 기반으로 합니다).</li> +</ol> + +<p>데이터베이스에 업데이트를 기록하는 조작도 이와 비슷하게 처리합니다, 단 데이터베이스 업데이트는 브라우저의 HTTP request가 <code>POST</code> request로 인코딩 되어야 합니다. </p> + +<h3 id="Doing_other_work">Doing other work</h3> + +<p>웹 어플리케이션의 일은 HTTP requests를 전달 받고 HTTP responses를 반환 하는 것 입니다. 데이터베이스와 상호작용 하여 정보를 얻어오거나 업데이트를 하는것은 매우 평범한 작업이지만 코드는 같은 시간에 다른 것들을 하거나 데이터 베이스와 상호작용을 하지 않을 수 있습니다.</p> + +<p>웹 어플리케이션의 수행할 수 있는 추가적인 작업에 대한 좋은 예는 사용자가 사이트에 등록 되어있는지 확인 하기위해 이메일을 보내는 것 입니다. 사이트는 로깅 또는 다른 작업을 수행 할 수 있습니다. </p> + +<h3 id="Returning_something_other_than_HTML">Returning something other than HTML</h3> + +<p>서버측 웹사이트 코드는 HTML 스니펫/파일만을 반환하지는 않습니다. 그 대신 다양한 파일들(text, PDF, CSV, etc.) 과 데이터(JSON, XML, etc.)를 동적으로 생성하여 반환 할 수 있습니다.</p> + +<p>({{glossary("AJAX")}})를 동적으로 업데이트 할 수 있도록 데이터를 웹 브라우저로 반환하는 아이디어는 꽤 오래있었습니다. 최근에는 "단일 페이지 앱" 인기가 있기 사작하였고, 전체의 웹 사이트는 필요한 경우 동적으로 업데이트되는 단일 HTML페이지로 작성 되었습니다. 이 스타일의 애플리케이션을 사용하여 만든 웹 사이트는 서버에서 해야 할 계산을 웹 브라우저로 이동시켜 웹 사이트가 기본 애플리케이션처럼 작동하는 것처럼 보일 수 있습니다 (반응이 빠른, 기타 등등.).</p> + +<h2 id="Web_frameworks_simplify_server-side_web_programming">Web frameworks simplify server-side web programming</h2> + +<p>서버측 웹 프레임 워크는 위에서 설명한 작업을 훨씬 쉽게 처리할 수 있는 코드를 제공합니다.</p> + +<p>그들이 수행하는 가장 중요한 작업 중 하나는 다양한 리소스 / 페이지에 대한 URL을 특정 처리기 기능에 매핑하는 간단한 메커니즘을 제공하는 것입니다. 이는 분리된 리소스의 각각 타입들이 관련된 코드를 보관하는 것을 쉽게 만들어 줍니다. 또한 유지 보수 측면에서도 이점이 있습니다, 핸들러 기능을 변경하지 않고도 한 곳에서 특정 기능을 제공하는 데 사용되는 URL을 변경할 수 있기 때문입니다.</p> + +<p>예를 들어, 2개의 뷰 함수를 2개의 URL에 매핑하는 다음의 Django (Python)코드를 보면. 첫 번째 패턴은 리소스 URL이 / best 인 HTTP 요청이 views 모듈의 index () 함수에 전달되도록합니다. "/ best / junior"패턴을 가진 요청은 대신 junior ()보기 기능으로 전달됩니다.</p> + +<pre class="brush: python"># file: best/urls.py +# + +from django.conf.urls import url + +from . import views + +urlpatterns = [ + # example: /best/ + url(r'^$', views.index), + # example: /best/junior/ + url(r'^junior/$', views.junior), +]</pre> + +<div class="note"> +<p><strong>Note</strong>: url () 함수의 첫 번째 매개 변수는 "정규 표현식"(RegEx 또는 RE)이라는 패턴 일치 기술을 사용하기 때문에 조금 이상하게 보일 수 있습니다 (예 : r' ^ junior / $ '). 위의 하드 코딩 된 값 대신 URL에서 패턴을 일치시키고 뷰 기능에서 매개 변수로 사용할 수있는 것 외에는 정규 표현식이 어떻게 작동하는지 알 필요가 없습니다. 예를 들어, 정말 간단한 RegEx는 "하나의 대문자와 일치하고 4 ~ 7 자의 소문자가옵니다"라고 말할 수 있습니다</p> +</div> + +<p>웹프레임 워크는 뷰 함수가 데이터베이스안의 정보를 가져오는 것 또한 쉽게 만들어 줍니다. 데이터 구조는 기본 데이터베이스에 저장할 필드를 정의하는 Python 클래스 인 모델에서 정의됩니다. "team_type"필드를 가진 Team이라는 모델이 있다면 간단한 쿼리 구문을 사용하여 특정 유형의 모든 팀을 되 찾을 수 있습니다.</p> + +<p>아래 예제는 정확한 (대소 문자 구분) <code>team_type</code>이 "junior"인 모든 팀의 목록을 가져옵니다. - 필드 이름 (<code>team_type</code>)과 두 번째 밑줄, 그리고 사용할 일치 유형 (이 경우 <code>정확한</code>). 다른 많은 유형의 경기가 있으며 데이지 체인 방식으로 경기를 진행할 수 있습니다. 우리는 또한 반환 된 결과의 순서와 수를 제어 할 수 있습니다. </p> + +<pre class="brush: python">#best/views.py + +from django.shortcuts import render + +from .models import Team + + +def junior(request): + list_teams = Team.objects.filter(team_type__exact="junior") + context = {'list': list_teams} + return render(request, 'best/index.html', context) +</pre> + +<p><code>junior()</code> 함수가 주니어 팀 목록을 얻은 후에 원래 <code>HttpRequest</code>, HTML 템플리트 및 템플리트에 포함될 정보를 정의하는 "컨텍스트"객체를 전달하여<code>render()</code> 함수를 호출합니다. <code>render()</code>함수는 컨텍스트와 HTML 템플릿을 사용하여 HTML을 생성하고 <code>HttpResponse</code>객체에 반환하는 편리한 함수입니다.</p> + +<p>분명히 웹 프레임 워크는 많은 다른 작업을 도와 줄 수 있습니다. 우리는 다음 기사에서 더 많은 이점과 일부 대중적인 웹 프레임 워크 선택에 대해 논의합니다.</p> + +<h2 id="Summary">Summary</h2> + +<p>이 시점에서 서버 측 코드가 수행해야하는 작업을 잘 살펴보고 서버 측 웹 프레임 워크가 이를 쉽게 수행 할 수있는 몇 가지 방법을 알고 있어야합니다.</p> + +<p>다음 모듈에서는 당신이 첫 번째 사이트에 가장 적합한 웹 프레임 워크를 선택할 수 있도록 도와 드리겠습니다</p> + +<p>{{PreviousMenuNext("Learn/Server-side/First_steps/Introduction", "Learn/Server-side/First_steps/Web_frameworks", "Learn/Server-side/First_steps")}}</p> diff --git a/files/ko/learn/server-side/first_steps/index.html b/files/ko/learn/server-side/first_steps/index.html new file mode 100644 index 0000000000..a8faa4352b --- /dev/null +++ b/files/ko/learn/server-side/first_steps/index.html @@ -0,0 +1,39 @@ +--- +title: Server-side website programming first steps +slug: Learn/Server-side/First_steps +translation_of: Learn/Server-side/First_steps +--- +<div>{{LearnSidebar}}</div> + +<p>서버사이드 프로그래밍 모듈에서 우리는 서버사이드 프로그래밍에 대해 몇 가지 근본적인 질문을 합니다. — "그게 뭐야?", "클라이언트 사이드 프로그래밍과 뭐가 달라?", "왜 쓸만해?". 여기서 우리는 여러분의 첫 웹사이트를 만드는 데에 필요한 가장 적합한 프레임워크를 어떻게 정하는 지에 대한 적절한 지도와 함께 가장 인기있는 서버 사이드 웹 프레임워크들의 개요를 제공합니다. 끝으로 높은 수준의 웹 서버 보안에 대한 소개를 제공합니다.</p> + +<h2 id="전제_조건">전제 조건</h2> + +<p>이 모듈을 시작하기 전에, 서버사이드 프로그래밍이나 혹은 사실상 다른 어떠한 프로그래밍 지식도 필요 하지 않습니다.</p> + +<p>"웹이 어떻게 동작하는가" 를 이해해야 합니다. 다음의 토픽들을 우선 읽어보는 것을 추천합니다.</p> + +<ul> + <li><a href="/en-US/docs/Learn/Common_questions/What_is_a_web_server">웹 서버란 무엇인가 (What is a web server</a>)</li> + <li><a href="/en-US/docs/Learn/Common_questions/What_software_do_I_need">웹사이트를 만들기 위해서는 어떤 소프트웨어가 필요한가 (What software do I need to build a website?</a>)</li> + <li><a href="/en-US/docs/Learn/Common_questions/Upload_files_to_a_web_server">어떻게 웹 서버에 파일을 업로드 하는가 (How do you upload files to a web server?</a>)</li> +</ul> + +<p>이러한 기본적인 이해가 있다면, 이 섹션의 모듈들을 공부할 준비가 되었습니다.</p> + +<h2 id="가이드">가이드</h2> + +<dl> + <dt>서버 사이드에 대한 소개 (<a href="https://developer.mozilla.org/ko/docs/Learn/Server-side/First_steps/Introduction">Introduction to the server side</a>)</dt> + <dd>MDN의 초급자 서버 사이드 프로그래밍 코스에 오신 것을 환영합니다! 첫 글에서는, '서버사이드란 무엇인가', '클라이언트 사이드 프로그래밍과 어떤 점이 다른가', 그리고 '왜 유용한가' 와 같은 질문들에 답하며 서버 사이드 프로그래밍을 상위 단계부터 살펴봅니다. 이 글을 읽고 난 후, 서버 사이드 코딩을 통해 웹사이트에 추가적인 작업들을 할 수 있다는 것을 이해하게 될 것입니다.</dd> + <dt>클라이언트 - 서버 개요 (<a href="https://developer.mozilla.org/ko/docs/Learn/Server-side/First_steps/Client-Server_overview">Client-Server overview</a>)</dt> + <dd>당신이 서버 사이드 프로그래밍의 목적과 잠재적인 이점에 대해 알고 있기 때문에, 이제 서버가 브라우저로 부터 "동적 요청"을 받으면 어떤 일이 일어나는 지를 자세히 알아보고자 합니다. 대부분의 웹사이트 서버 사이드 코드는 요청 및 응답을 비슷한 방식으로 다루기 때문에, 이것은 당신이 코드를 짤 때 무엇을 해야 하는지 이해하도록 도울 것입니다.</dd> + <dt>서버 사이드 웹 프레임워크 (<a href="/en-US/docs/Learn/Server-side/First_steps/Web_frameworks">Server-side web frameworks</a>)</dt> + <dd>마지막 글은 서버 사이드 웹 어플리케이션이 웹 브라우저의 요청에 응답하기 위해 무엇을 해야하는 지를 보여줍니다. 이제 웹 프레임워크가 어떻게 이러한 일들을 간소화 하는지 보여주고, 당신이 첫 서버 사이드 웹 어플리케이션에 맞는 프레임워크를 선택하도록 도울 것입니다. </dd> + <dt>웹사이트 보안 (<a href="/en-US/docs/Learn/Server-side/First_steps/Website_security">Website security</a>)</dt> + <dd>웹사이트 보안은 웹사이트 설계 및 이용의 모든 측면에서 주의를 필요로 합니다. 이 입문 글이 당신을 웹사이트 보안 전문가로 만들어주지는 않지만, 가장 일반적인 위협들로 부터 웹 어플리케이션을 튼튼하게 만드는 첫 중요한 단계들을 이해하게끔 도울 것입니다. </dd> +</dl> + +<h2 id="평가">평가</h2> + +<p>이 "개요" 모듈은 아직 어떠한 코드도 보여주지 않았기 때문에 어떠한 평가도 없습니다. 우리는 현 시점에서, 당신이 서버 사이드 프로그래밍을 통해 어떤 기능들을 보여줄 수 있는지 제대로 이해하고, 당신의 첫 웹사이트를 만드는데에 어떤 서버 사이드 웹 프레임 워크를 사용할 지 결정했기를 바랍니다.</p> diff --git a/files/ko/learn/server-side/first_steps/introduction/index.html b/files/ko/learn/server-side/first_steps/introduction/index.html new file mode 100644 index 0000000000..aa635c6d37 --- /dev/null +++ b/files/ko/learn/server-side/first_steps/introduction/index.html @@ -0,0 +1,184 @@ +--- +title: Introduction to the server side +slug: Learn/Server-side/First_steps/Introduction +tags: + - 서버 + - 서버측 프로그래밍 + - 초보자 +translation_of: Learn/Server-side/First_steps/Introduction +--- +<div>{{LearnSidebar}}</div> + +<div>{{NextMenu("Learn/Server-side/First_steps/Client-Server_overview", "Learn/Server-side/First_steps")}}</div> + +<p class="summary">MDN의 초심자용 서버측 프로그래밍 코스에 오신 것을 환영합니다! 첫번째 기사는 높은 수준의 서버측 프로그래밍을 살펴보고, "이게 뭐야?" , "클라이언트 측 프로그래밍과 어떻게 다르지?", 그리고 "이게 왜 유용한데?"같은 질문에 답할 것입니다. 이 기사를 읽은 뒤 당신은 웹 사이트가 서버측 코딩을 통해 이용 할 수 있는 추가적인 효과를 이해 할 수 있을것 입니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">선수 과목:</th> + <td>기본적인 컴퓨터 활용법. 웹 서버가 무엇인지에 대한 기본적인 이해.</td> + </tr> + <tr> + <th scope="row">목적:</th> + <td>서버 측 프래그래밍 무엇이고 어떤 일을 할 수 있는지 그리고 클라이언트 프로그래밍과 어떤점이 다른지에 대해 익숙해 지기.</td> + </tr> + </tbody> +</table> + +<p>대부분의 큰 사이트들은 동적으로 보여주기 위한 다양한 데이터가 필요 할 때 서버측 코드를 사용합니다, 일반적으로 서버에있는 데이터베이스에 저장된 데이터를 빼내어 일부 코드를 통해 보일 수 있도록 클라이언트에게 송신합니다(예: HTML 그리고 JavaScript). 아마도 서버측 코드의 큰 장점은 개별 사용자를 위한 맞춤 웹사이트 컨텐츠를 제공 한다는 것 입니다. 동적 사이트는 사용자의 선호도 및 습관에 따라 더 관련성이 높은 콘텐츠를 강조 표시 할 수 있습니다. 또한 이것은 사이트를 저장된 개인 선호와 정보를 사용하기 쉽게 만들어 줍니다 — 예를 들면 후속 지급을 간소화 하기 위한 저장된 신용카드 정보의 재사용. 심지어 사이트 외부 사용자와의 상호 작용을 허용하고 전자 메일 또는 다른 채널을 통해 알림 및 업데이트를 보냅니다. 이러한 모든 기능을 통해 사용자와의 관계를 더욱 깊게 할 수 있습니다.</p> + +<p>현대의 전 세계 웹 개발자들은 서버측 개발을 공부하는 것을 권고 하고 있습니다.</p> + +<h2 id="서버측_웹_사이트_프로그래밍이_무엇인가요">서버측 웹 사이트 프로그래밍이 무엇인가요?</h2> + +<p><a href="/en-US/docs/Learn/Common_questions/What_is_a_web_server">web servers</a>와 통신하는 웹 브라우저는 <strong>H</strong>yper<strong>T</strong>ext <strong>T</strong>ransport <strong>P</strong>rotocol ({{glossary("HTTP")}})을사용하고 있습니다. 당신이 웹 페이지의 링크를 클릭하거나 폼을 전송하거나 검색을 시작할 때 당신의 웹 브라우저는<strong> HTTP request</strong>를 목적 서버에 전달합니다. 요청에는 영향을받는 리소스를 식별하는 URL, 필요한 작업을 정의하는 메서드가 포함됩니다 (예를 들면 리소스를 가져 오거나, 삭제하거나 게시하는 방법), 그리고 URL매개변수(<a href="https://en.wikipedia.org/wiki/Query_string">query 문자열</a>을 통해 전송된 필드 값-쌍), POST 데이터 (<a href="/en-US/docs/Web/HTTP/Methods/POST">HTTP POST method</a>에 의해 전송된 데이터), 또는{{glossary("Cookie", "associated cookies")}}를 이용하여 인코딩된 추가 정보를 포함 할 수 있습니다.</p> + +<p>웹 서버는 클라이언트의 요청이 오길 기다리고, 요청이 도착하면 작업을 진행하여, 웹 브라우저에 <strong>HTTP 응답</strong> 메시지를 보냅니다. 그 응답은 요청이 성공 또는 실패를 지시하는 상태 라인을 포함하고 있습니다 (예: "HTTP/1.1 200 OK" for success). 요청에 대한 응답이 성공적이라면 본문은 요청 리소스(예. 새로운 HTML 페이지, 또는 이미지, 기타 등등...)를 포함 할 것이며 이는 웹 브라우저에 보여질 수 있습니다.</p> + +<h3 id="정적_웹_사이트(Static_sites)">정적 웹 사이트(Static sites)</h3> + +<p><em>아래의 다이어그램은 정적사이트의 기본적인 웹 구조를 보여주고 있습니다</em>(정적 사이트는 특별한 리소스 요청이 들어올 때 서버에서 하드 코딩된 동일한 콘텐츠를 반환합니다). 사용자가 페이지를 탐색하거나, 브라우저가 지정된 URL에 HTTP "GET"요청을 보낼 때 서버는 파일 시스템에서 요청한 문서를 검색하고 문서와 <a href="/en-US/docs/Web/HTTP/Status#Successful_responses">success status</a> (보통 200 OK)를 포함한 HTTP응답을 반환 합니다. 만약 어떠한 이유 때문에 파일을 검색하면 error status(<a href="/en-US/docs/Web/HTTP/Status#Client_error_responses">client error responses</a> 그리고 <a href="/en-US/docs/Web/HTTP/Status#Server_error_responses">server error responses</a>를 참고 하십시오)가 반환됩니다.</p> + +<p><img alt="A simplified diagram of a static web server." src="https://mdn.mozillademos.org/files/13841/Basic%20Static%20App%20Server.png" style="height: 223px; width: 800px;"></p> + +<h3 id="동적_웹_사이트(Dynamic_sites)">동적 웹 사이트(Dynamic sites)</h3> + +<p>동적 웹 사이트는 필요할 때에 동적으로 응답 콘텐츠가 생성 됩니다. 동적 웹사이트의 웹 페이지는 보통 HTML 템플릿에 있는 자리 표시자에 데이터베이스에서 가져온 데이터를 넣어 생성 됩니다 (이 방법은 많은 양의 콘텐츠를 저장하기에 정적 웹 사이트를 이용 하는 것 보다 효과적 입니다). 동적 웹사이트는 사용자또는 저장된 환경을 기반으로 URL에 대해 다른 데이터를 반환 할 수 있으며, 응답을 반환하는 과정에서 다른 작업을 수행 할 수 있습니다(예: 알림 보내기).</p> + +<p>동적 웹사이트를 지원하는 코드는 서버에서 실행 되어야 합니다. 이러한 코드를 만드는 것은 "<strong>server-side programming</strong>"이라고 알려져 있습니다 (또는 "<strong>back-end scripting</strong>"이라고 불리기도 합니다).</p> + +<p>아래의 다이어그램은 동적 웹 사이트의 간단한 구조를 보여주고 있습니다. 이전 다이어 그램과 같이, 브라우저는 HTTP 요청을 서버에 보내고, 서버는 요청을 처리하고 적절한 HTTP응답을 반환합니다. 정적 리소스의 요청은 정적 사이트와 같은 방법으로 처리 합니다(정적 파일은 변하지 않는 파일입니다 — 전형적으로: CSS, JavaScript, Images, pre-created PDF files 등등). </p> + +<p><img alt="A simplified diagram of a web server that uses server-side programming to get information from a database and construct HTML from templates. This is the same diagram as is in the Client-Server overview." src="https://mdn.mozillademos.org/files/13839/Web%20Application%20with%20HTML%20and%20Steps.png"></p> + +<p>동적 리소스를 위한 요청은 (2) 서버측 코드에 대신 전달 됩니다(<em>다이어그램에서 </em> <em>Web Application</em>으로 보이는 부분). "동적 응답"을 위해 서버는 응답을 해석하여 필요한 정보를 데이터 베이스에서 읽고(3), 탐색한 데이터와 HTML템플릿을 결합하고(4), 생성된 HTML을 포함한 응답을 다시 보내줍니다(5,6). </p> + +<div> +<h2 id="서버측과_클라이언트측의_프로그래밍은_같은가요">서버측과 클라이언트측의 프로그래밍은 같은가요?</h2> +</div> + +<p>다시 돌아와서 서버측에 관여하는 코드와 클라이언트 측에 관여하는 코드를 살펴 봅시다. 각각의 케이스마다 코드는 명확히 다릅니다:</p> + +<ul> + <li>그들은 관심과 목적이 서로 다릅니다.</li> + <li>일반적으로 같은 프로그래밍 언어를 쓰지 않습니다( JavaScript는 예외적으로 서버와 클라이언트측 둘다 사용 할 수 있습니다).</li> + <li>그들은 다른 운영체제 환경에서 수행 됩니다.</li> +</ul> + +<p>브라우저에서 실행되는 코드는 <strong>client-side code</strong>라고 알려져 있습니다. <strong>client-side code</strong>의 주 관심사는 렌더링된 웹페이지의 모양과 행동을 개선시키는 것 입니다. 이것은 UI 구성 요소 선택 및 스타일 지정, 레이아웃 만들기, 탐색, 양식 유효성 검사 등을 포함 하고 있습니다. 대조적으로, server-side 웹 사이트 프로그래밍은 대부분 브라우저의 요청에 대한 응답으로 어떤 컨텐츠를 반환하는지 선택하는것을 포함 합니다. Server-side code는 제출 된 데이터 및 요청의 유효성 검사, 데이터 저장 및 검색을위한 데이터베이스 사용, 필요에 따라 올바른 데이터 전송과 같은 작업을 처리합니다.</p> + +<p>클라이언트 측 코드는 <a href="/en-US/docs/Learn/HTML">HTML</a>, <a href="/en-US/docs/Learn/CSS">CSS</a>, 그리고 <a href="/en-US/docs/Learn/JavaScript">JavaScript</a>로 작성됩니다— 이것들은 웹 브라우저 안에서 실행되고 기본운영체제와 연결되지 않거나 아주 약간 연결 됩니다(파일 시스템의 연결의 제한이 포함 되어 있습니다). 웹 개발자는 모든 사용자가 웹 사이트를 보는 데 사용할 수있는 브라우저를 조작 할 수 없습니다 —브라우저는 클라이언트 측 코드 기능과 일관성없는 수준의 호환성을 제공하며, 클라이언트 측 프로그래밍의 어려움은 브라우저 지원의 차이를 정상적으로 처리 하는 것 입니다.</p> + +<p>서버측 코드는 다양한 프로그래밍 언어로 작성 될 수 있습니다 — 대중적인 서버측 웹 언어를 포한 한 예로 PHP, Python, Ruby 그리고 C#. 서버측 코드는 서버의 운영체제와 모든 접속권한을 가지며, 개발자는 그들이 원하는 프로그래밍 언어(그리고 특정 버전)를 사용할 수 있습니다.</p> + +<p>개발자는 일반적으로 <strong>web frameworks</strong>를 이용하여 코드를 작성 합니다. 웹 프레임 워크는 일반적인 문제를 해결하고 개발 속도를 높이며 특정 도메인에서 직면하는 다양한 유형의 작업을 단순화하도록 설계된 함수, 객체, 규칙 및 기타 코드 구성 요소의 모음입니다. 다시 말하지만 클라이언트와 서버 측 코드 모두 프레임 워크를 사용하지만 도메인은 매우 다르므로 프레임 워크도 다릅니다. 클라이언트 측 웹 프레임 워크는 레이아웃 및 프리젠 테이션 작업을 단순화하는 반면 서버 측 웹 프레임 워크는 직접 구현해야하는 많은 "공통"웹 서버 기능을 제공합니다(예: 세션 지원, 사용자와 인증을 지원, 데이터베이스와 쉬운 연결, 템플리트 라이브러리, 기타 등등.).</p> + +<div class="note"> +<p><strong>Note</strong>: 클라이언트 측 프레임워크는 때때로 클라이언트측 코드를 개발하는 속도를 올릴 수 있게 도와주도록 사용하지만, 당신은 모든 코드를 직접 작성 할 수도 있습니다; 사실은 당신이 작고, 간단한 사이트의 UI를 만든다면 당신이 직접 작성하는 코드가 더 빠르고 효과적일수 있습니다. 이와 대조적으로, 당신은 서버측 웹 앱의 컴포넌트를 프레임 워크 없이 작성 하는것은 거의 고려 하지 않을 것 입니다 — 파이썬에서 HTTP 서버와 같은 중요한 기능구현을 처음부터 하는 것은 어렵지만 Django와 같은 Python 웹 프레임 워크는 다른 유용한 도구와 함께 즉시 사용할 수있는 도구를 제공합니다.</p> +</div> + +<div> +<h2 id="서버측에서_무엇을_할_수_있나요">서버측에서 무엇을 할 수 있나요?</h2> + +<p>서버 측 프로그래밍은 개별 사용자에 맞게 정보를 효율적으로 전달할 수있게 해주고 사용자 경험을 훨씬 향상시킬 수 있기 때문에 매우 유용합니다.</p> +</div> + +<p>Amazon과 같은 회사는 서버 측 프로그래밍을 사용하여 제품 검색 결과를 작성하고 고객 선호도 및 이전 구매 습관을 기반으로 한 제품 제안, 구매 단순화 등을 수행합니다. 은행은 고객 정보를 저장하고 권한이있는 사용자만 보고 거래 할 수 있도록 서버 측 프로그래밍을 사용합니다. Facebook, Twitter, Instagram 및 Wikipedia와 같은 기타 서비스는 서버 측 프로그래밍을 사용하여 재미있는 컨텐츠에 대한 액세스를 강조, 공유 및 제어합니다.</p> + +<p>서버 측 프로그래밍의 일반적인 용도와 이점은 다음과 같습니다. 겹치는 부분이 있음을 알 수 있습니다!</p> + +<h3 id="효율적인_저장소와_정보_전달">효율적인 저장소와 정보 전달</h3> + +<p>Amazon에서 얼마나 많은 제품을 사용할 수 있는지 상상해보십시오. Facebook에 얼마나 많은 게시물이 작성되었는지 상상해보십시오. 각 제품 또는 게시물에 대해 별도의 정적 페이지를 만드는 것은 완전히 비효율적입니다.</p> + +<p>서버 측 프로그래밍을 사용하면 정보를 데이터베이스에 저장하고 HTML 및 기타 유형의 파일(예: PDF, 이미지, etc.)을 동적으로 생성하고 반환 할 수 있습니다. 또한 적절한 클라이언트 웹 프레임워크로 렌더링하기 위해 간단한 데이터({{glossary("JSON")}}, {{glossary("XML")}}, etc.)도 반환 할 수 있습니다 (이렇게하면 서버의 처리 부담과 전송해야하는 데이터의 양이 줄어 듭니다.).</p> + +<p>서버는 데이터베이스에서 정보를 전송하는 것에 국한되지 않고, 소프트웨어 도구의 결과 또는 통신 서비스의 데이터를 반환 할 수도 있습니다. 콘텐츠는 수신중인 클라이언트 장치의 유형을 대상으로 할 수도 있습니다.</p> + +<p>왜냐하면 데이터베이스의 정보는 다른 비즈니스 시스템에 의해 간단히 공유되고 업데이트 될 수 있기 때문입니다(예를 들어, 제품이 온라인 또는 상점에서 판매 될 때, 상점은 재고 데이터베이스를 갱신 할 수 있습니다).</p> + +<div class="note"> +<p><strong>Note</strong>: 효율적인 저장 및 정보 전달을위한 서버 측 코드의 이점을보기 위해 상상력을 집중하지 않아도됩니다:</p> + +<ol> + <li>Amazon 또는 기타 전자 상거래 사이트로 이동하십시오.</li> + <li>여러 개의 키워드를 검색하고 결과가 나타나더라도 페이지 구조가 변하지 않는지 유의 하십시오</li> + <li>2 개 또는 3 개의 다른 제품을 엽니 다. 공통된 구조와 레이아웃을 갖는지에 대해 다시 유의하십시오. 다른 제품의 내용은 데이터베이스에서 가져 왔습니다.</li> +</ol> + +<p>일반적인 검색 용어 ( "fish", say)의 경우 문자 그대로 수백만 개의 반환 값을 볼 수 있습니다. 데이터베이스를 사용하면 이러한 정보를 효율적으로 저장하고 공유 할 수 있으며 정보의 표시를 한 곳에서만 제어 할 수 있습니다.</p> +</div> + +<h3 id="맞춤형_사용자_경험(user_experience)">맞춤형 사용자 경험(user experience)</h3> + +<p>서버는 사용자에게 편안함과 맞춤형 사용자 경험을 제공하기 위해 사용자의 정보를 사용하거나 저장 할 수 있습니다. 예를 들어 많은 사이트들은 신용카드 세부 정보를 저장하므로 그것을 다시 입력 할 필요가 없습니다. Google Maps와 같은 사이트는 라우팅 정보를 제공하고 검색 결과에서 지역 비즈니스를 강조 표시하기 위해 집과 현재 위치를 사용합니다.</p> + +<p>사용자의 습관에 대한 면밀한 분석은 그들의 흥미를 예측하거나 사용자 맞춤 응답과 알림을 주는데에 사용 될 수 있습니다, 예를 들어 이전에 방문했거나 인기있는 위치 목록을지도에서 볼 수 있습니다.</p> + +<div class="note"> +<p><strong>Note</strong>: 익명의 사용자로 <a href="https://maps.google.com/">Google Maps</a>로 이동하고 <strong>길 찾기</strong> 버튼을 선택한 다음 여행의 시작 및 종료 지점을 입력하십시오. 이제 Google 계정을 사용하여 시스템에 로그인하십시오 (이 과정에 대한 정보는 아래에서 방향을 선택하는 패널에 나타납니다). 이제 웹 사이트에서 시작 지점과 종료 지점으로 집과 직장 위치를 선택할 수 있습니다 (아직 완료하지 않았다면이 세부 정보를 저장하십시오).</p> +</div> + +<h3 id="컨텐츠에_대한_접근_제한">컨텐츠에 대한 접근 제한</h3> + +<p>서버측 프로그래밍을 통해 사용자만 접근 할 수 있도록 제한하거나 사용자가 볼수 있는 정보만 제공 할 수 있습니다.</p> + +<p>실제 사례는 다음과 같습니다:</p> + +<ul> + <li>Facebook과 같은 소셜 네트워크는 사용자가 자신의 데이터를 완벽하게 제어 할 수 있도록 허용하지만 친구 만 보거나 댓글을 달 수 있습니다. 사용자는 자신의 데이터를 볼 수있는 사용자를 결정하고, 확장자별로 피드에 데이터가 표시됩니다 — 승인은 사용자 환경의 핵심 부분입니다!</li> + <li> + <p>현재 당신이 보고 있는 이 사이트는 모든 사람들이 기사를 볼 수 있지만 로그인 한 사용자만 내용을 편집 할 수 있습니다. 이를 시도하려면 이 페이지 상단의 편집 버튼을 클릭하십시오 - 로그인되어있는 경우 편집보기가 표시됩니다. 로그인하지 않으면 가입 페이지로 이동합니다.</p> + </li> +</ul> + +<div class="note"> +<p><strong>Note</strong>: 콘텐츠에 대한 액세스가 제어되는 다른 실제 사례를 고려하십시오. 예를 들어 은행의 온라인 사이트로 이동하면 무엇을 볼 수 있습니까? 계정에 로그인 - 어떤 추가 정보를보고 수정할 수 있습니까? 은행만 변경 될 수 있음을 알 수 있는 정보는 무엇입니까?</p> +</div> + +<h3 id="세션과_상태_저장">세션과 상태 저장</h3> + +<p>개발자는 서버 프로그래밍을 사용하여<strong> sessions</strong>을 만들 수 있습니다 — 서버가 현재 사이트의 사용자 정보를 저장하거나 정보에 기반한 다른 응답을 보낼 수 있는 기본적인 메커니즘 입니다. 예를 들어, 사이트에서 사용자가 이전에 로그인하여 이메일 또는 주문 내역에 대한 링크를 표시하거나 간단한 게임의 상태를 저장하여 사용자가 사이트를 다시 이용할 때 떠났던 부분부터 다시 할 수 있습니다.</p> + +<div class="note"> +<p><strong>Note</strong>: 구독 모델이있는 신문 사이트를 방문하여 많은 수의 탭을 엽니다(예: <a href="http://www.theage.com.au/">The Age</a>). 몇 시간 / 일 동안 사이트를 계속 방문하십시오. 결국 구독 방법을 설명하는 페이지로 리디렉션되기 시작하고 기사에 액세스 할 수 없게됩니다. 이 정보는 쿠키에 저장된 세션 정보의 예 입니다.</p> +</div> + +<h3 id="알림과_대화">알림과 대화</h3> + +<p>서버는 일반적이거나 유저에 특화된 알림을 웹사이트 자신이나 이메일, SMS, 인스턴트 메시징, 비디오 대화, 또는 다른 통신 서비스를 통해 보낼 수 있습니다</p> + +<p>몇개의 예가 포함 되어 있습니다:</p> + +<ul> + <li>Facebook과 Twitter 당신의 새로운 연락에 대한 알림을 이메일이나 SMS로 보내 줍니다.</li> + <li>Amazon은 당신 관심을 가질만한 이미 구입했거나 본 제품과 유사한 제품을 제안하는 제품 전자 메일을 정기적으로 보냅니다.</li> + <li>웹서버는 사이트의 관리자에게 서버의 메모리가 부족하거나 의심스러운 활동을 하는 사용자가 있을때 메시지를 보내서 경고 할 수 있습니다.</li> +</ul> + +<div class="note"> +<p><strong>Note</strong>: 가장 일반적인 유형의 알림은 "등록 확인"입니다. 관심있는 큰 사이트 (Google, Amazon, Instagram 등)를 선택하고 이메일 주소를 사용하여 새 계정을 만드십시오. 귀하는 귀하의 등록을 확인하거나 귀하의 계정을 인증하기 위해 승인을 요구하는 이메일을 곧 받게 될 것입니다.</p> +</div> + +<h3 id="정보_분석">정보 분석</h3> + +<p>웹사이트는 사용자에대한 많은 정보를 수집할 수 있습니다: 그들이 뭘 검색하는지, 그들이 뭘 사는지, 그들이 뭘 추천하는지, 그들이 각 페이지 마다 얼마나 머무르는지. 서버 측 프로그래밍을 사용하여 데이터의 분석을 기반으로 응답을 구체화 할 수 있습니다.</p> + +<p>그 예로, Amazon과 Google둘다 전에 검색하였던 결과(및 구매)를 바탕으로 제품 광고를 합니다.</p> + +<div class="note"> +<p><strong>Note</strong>: Facebook 사용자인 경우 기본 피드로 이동하여 게시물 스트림을 확인하십시오. 일부 게시물의 숫자 순서가 어긋나는 것에 유의하십시오. 특히 "좋아요"가 많은 게시물은 최근 게시물보다 목록에서 더 자주 표시됩니다. 또한 어떤 광고가 게재 되고 있는지 살펴보십시오. 다른 사이트에서 봤던 광고를 볼 수 있습니다. 콘텐츠 및 광고를 강조하는 Facebook의 알고리즘은 약간의 수수께끼 일 수 있지만 좋아하는 것과 보는 습관에 달려 있다는 것은 분명합니다.</p> +</div> + +<h2 id="요약">요약</h2> + +<p>축하합니다, 당신은 첫번째 기사인 서버측 프로그래밍을 끝까지 읽으셨습니다. </p> + +<p>당신은 이제 서버측 코드가 웹 서버 위에서 실행되고 그것의 주 역할은 사용자에게 전달하는 정보를 컨트롤 한다는걸 알게 되었습니다(클라이언트 측 코드는 사용자에게 데이터의 구조와 표현을 처리합니다). 또한 사용자별로 맞춤 설정된 정보를 효율적으로 제공하고 서버 측 프로그래머 일 때 수행 할 수있는 작업에 대한 좋은 아이디어가있는 웹 사이트를 만들 수 있으므로 유용하다는 점도 이해해야합니다.</p> + +<p>마지막으로, 서버 측 코드는 여러 프로그래밍 언어로 작성 될 수 있으며 전체 프로세스를보다 쉽게하기 위해 웹 프레임 워크를 사용해야한다는 것을 이해해야합니다. </p> + +<p>향후 기사에서는 첫 번째 사이트에 가장 적합한 웹 프레임 워크를 선택할 수 있도록 도와 드리겠습니다. 다음은 주요 클라이언트 - 서버 상호 작용에 대해 좀 더 자세하게 설명하겠습니다.</p> + +<p>{{NextMenu("Learn/Server-side/First_steps/Client-Server_overview", "Learn/Server-side/First_steps")}}</p> diff --git a/files/ko/learn/server-side/first_steps/web_frameworks/index.html b/files/ko/learn/server-side/first_steps/web_frameworks/index.html new file mode 100644 index 0000000000..24c252285a --- /dev/null +++ b/files/ko/learn/server-side/first_steps/web_frameworks/index.html @@ -0,0 +1,312 @@ +--- +title: Server-side web frameworks +slug: Learn/Server-side/First_steps/Web_frameworks +translation_of: Learn/Server-side/First_steps/Web_frameworks +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Server-side/First_steps/Client-Server_overview", "Learn/Server-side/First_steps/Website_security", "Learn/Server-side/First_steps")}}</div> + +<p class="summary">이전 기사에서는 웹 클라이언트와 서버 간의 통신 모습, HTTP 요청 및 응답의 성격, 서버 측 웹 애플리케이션이 웹 브라우저의 요청에 응답하기 위해 수행해야하는 작업에 대해 설명했습니다. 이러한 지식을 바탕으로, 지금 시간에는 웹 프레임 워크가 어떻게 그러한 작업을 간단히 만드는지 탐색하고, 당신의 첫 서버측 애플리케이션을 위한 프레임 워크를 어떻게 선택하는지 의견을 드리겠습니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Prerequisites:</th> + <td>기본적인 컴퓨터 활용법. HTTP 요청을 서버측 코드가 어떻게 다루고 응답하는지에 대한 높은 수준의 이해 (<a href="https://developer.mozilla.org/ko/docs/Learn/Server-side/First_steps/Client-Server_overview">Client-Server overview</a>를 참고 하십시오).</td> + </tr> + <tr> + <th scope="row">Objective:</th> + <td>웹 프레임 워크가 어떻게 서버측 코드를 개발/유지하기 간단하게 만들 수 있는지 이해하고 , 독자들이 그들의 개발에 어떤 프레임워크를 선택 할지에 대해 생각해보게 합니다.</td> + </tr> + </tbody> +</table> + +<p>이 섹션에서 실제 웹 프레임 워크에서 가져온 코드 조각을 설명할 것 입니다. 지금 <strong>전부</strong> 이해가 가지 않는것에 대해 당황하지 마세요; 우리는 프레임 워크 특정 모듈의 코드를 통해 작업 할 것입니다.</p> + +<h2 id="개요">개요</h2> + +<p>서버측 웹 프레임워크("웹 어플리케이션 프레임워크"라고 알려진)는 작성하기 쉽고, 웹 어플리케이션을 유지및 보수하기 쉽게 만드는 소프트웨어 프레임 워크입니다. 적절한 URL핸들러로 라우팅, 데이테베이스와 상호작용, 유저 인증과 세션 지원, 출력 형식(예: HTML, JSON, XML), 웹 공격에 대처하기 위한 보안 강화 같은 일반적인 웹 개발 작업을 단순화하는 도구와 라이브러리를 제공합니다.</p> + +<p>다음 섹션은 어떻게 웹 프레임워크가 웹 애플리케이션 개발을 쉽게 하는지 더 상세히 살펴 보겠습니다. 우리는 당신이 사용할 웹 프레임워크를 선택하는 기준을 설명하고 몇 가지 옵션을 나열하겠습니다.</p> + +<h2 id="웹_프레임워크는_무엇을_지원하는가">웹 프레임워크는 무엇을 지원하는가?</h2> + +<p>웹 프레임워크는 일반적인 웹 개발 작업을 단순화 하는 도구와 라이브러리를 제공합니다. 당신은 서버측 웹 프레임 워크를 사용하지 않을 수 있지만 이는 권고 되지 않습니다 — 서버측 웹 프레임워크를 사용하면 당신의 삶이 더 편해질 것입니다.</p> + +<p>이 섹션에서는 웹 프레임워크가 제공하는 몇몇 기능에 대해 논의 하겠습니다(모든 프레임 워크가 그 기능을 제공하지는 않습니다!)</p> + +<h3 id="Work_directly_with_HTTP_requests_and_responses">Work directly with HTTP requests and responses</h3> + +<p>우리가 마지막 기사에서 봤듯이 웹 서버와 브라우저는 HTTP protocol을 통해 통신합니다 — 서버는 브라우저에서 오는 HTTP요청을 기다리고, HTTP응답에 정보를 반환 합니다. 웹 프레임워크는 이러한 요청과 응답을 할 서버측 코드를 만드는데 작성할 문법을 단순화 합니다. 이것은 당신의 일과 상호작용을 쉽게 하고, 저수준 네트워킹 프리미티브보다 높은 수준의 코드를 이용한다는 것을 의미합니다.</p> + +<p>Django (Python) 웹 프레임워크가 어떻게 작동 하는지의 대한 예가 아래에 나와 있습니다. 모든 "view"함수는(요청 핸들러) 요청 정보가 포함된<code>HttpRequest</code>객체를 받고, 형식화된 출력(이번 케이스에선 string)이 있는<code>HttpResponse</code> 객체를 반환합니다.</p> + +<pre class="brush: python"># Django view function +from django.http import HttpResponse + +def index(request): + # Get an HttpRequest (request) + # perform operations using information from the request. + # Return HttpResponse + return HttpResponse('Output string to return') +</pre> + +<h3 id="Route_requests_to_the_appropriate_handler">Route requests to the appropriate handler</h3> + +<p>대부분의 사이트는 여러개의 다른 리소스를 특정된 URL을 통해 접근 할 수 있도록 제공합니다. 통합된 함수로 모든것을 처리하는건 유지하기가 매우 힘듭니다, 그래서 웹 프레임워크는 특별한 처리 함수로 URL패턴을 매핑하는 기능을 제공합니다. 이러한 접근 방법은 유지 보수 기간에 이점이 있습니다. 왜냐하면 기본 코드를 변경하지 않고도 특정 기능을 제공하는 데 사용되는 URL을 변경할 수 있기 때문입니다.</p> + +<p>각각의 프레임 워크들은 다른 매핑 메커니즘을 사용합니다. 예를 들면 Flask (Python) 웹 프레임 워크는데코레이터를 사용하여 view함수에 경로를 추가합니다.</p> + +<pre class="brush: python">@app.route("/") +def hello(): + return "Hello World!"</pre> + +<p>Django는 개발자가 URL 패턴과 뷰 함수 사이에 URL 매핑 목록을 정의 할 것을 기대합니다.</p> + +<pre class="brush: python">urlpatterns = [ + url(r'^$', views.index), + # example: /best/myteamname/5/ + url(r'^(?P<team_name>\w.+?)/(?P<team_number>[0-9]+)/$', views.best), +] +</pre> + +<h3 id="Make_it_easy_to_access_data_in_the_request">Make it easy to access data in the request</h3> + +<p>데이터는 다양한 방법으로 HTTP응답에 인코딩 될 수 있습니다. 서버에서 파일이나 데이터를 얻기 위한 HTTP GET 요청은 URL인자나 URL구조를 요구한 데이터를 인코딩 할 수 있습니다. 서버에 있는 리소스를 업데이트를 요청하는 HTTP <code>POST</code>는 요청 본문에 "POST data"로 업데이트 정보를 대신 포함합니다. 또한 HTTP 요청은 클라이언트 측 쿠키에서 현재 세션 또는 사용자에 관한 정보를 포함 할 수있습니다.</p> + +<p>웹 프레임 워크는 정보에 액세스하기위한 프로그래밍 언어에 적합한 메커니즘을 제공합니다. 예를 들어 Django가 모든 뷰 함수에 전달하는 HttpRequest 객체는 대상 URL, 요청 유형 (예 : HTTP GET), GET 또는 POST 매개 변수, 쿠키 및 세션 데이터 등에 접근 하기 위한 메소드 및 속성을 포함합니다. Django는 URL 매퍼에 "캡처 패턴"을 정의한 URL 구조로 인코딩 된 정보를 전달할 수도 있습니다 (위 섹션의 마지막 코드 단편 참조).</p> + +<h3 id="Abstract_and_simplify_database_access">Abstract and simplify database access</h3> + +<p>웹 사이트는 사용자와 사용자에 대한 정보 공유를 위한 데이터를 저장 하기 위해서 데이터베이스를 사용합니다. 웹 프레임 워크는 종종 데이터베이스 읽기, 쓰기, 쿼리, 삭제 조작을 추상화 할 수 있는 데이터베이스 계층을 제공 합니다. 이러한 추상 계층을 객체 관계형 매퍼(ORM)라고 합니다.</p> + +<p>ORM을 사용 하는 것은 2가지 장점이 있습니다:</p> + +<ul> + <li>사용하던 코드를 수정하지 않고 기본 데이터베이스를 바꿀 수 있습니다. 이것을 통해 개발자가 사용법에 따른 데이터베이스의 특성을 최적화 할 수 있습니다.</li> + <li>기본적인 데이터의 확인은 프레임워크 안에서 구현 될 수 있습니다. 이를 통해 올바른 타입의 데이터베이스 필드에 데이터를 저장하는지, 올바른 타입인지(예: 이메일 주소), 악의적인 방식 (크래커는 특정 코드 패턴을 사용하여 데이터베이스 레코드를 지우는 것과 같은 나쁜 행동을 할 수 있습니다)인지 쉽고 안전하게 확인 할 수 있습니다.</li> +</ul> + +<p>예를들어 Django 웹 프레임워크는 ORM을 제공하고 레코드 구조 모델로 정의하는데 사용한 객체를 참조합니다. 모델은 저장 될 필드 유형을 지정하며, 저장 될 수있는 정보에 대한 필드 레벨 검증을 제공 할 수 있습니다(예 : 이메일 입력란은 유효한 이메일 주소 만 허용). 또한 필드 정의는 최대 크기, 기본 값, 선택 목록 옵션, 문서를 위한 도움말, 양식 레이블 텍스트 등을 지정할 수도 있습니다. 모델은 코드와 별도로 변경 될 수있는 구성 설정이므로 기본 데이터베이스에 대한 정보는 명시하지 않습니다.</p> + +<p>첫번째 코드 스니펫은 아래에 보이는 매우 간단한 <code>Django</code> 모델인 <code>Team</code>객체 입니다. 이 객체는 팀 이름과 팀의 레벨을 문자 필드로 저장하고 각각의 레코드마다 최대 한도의 문자 길이를 저장 합니다. <code>team_level</code>은 선택 필드이므로 우리는 디폴트 값과 함께 표시할 선택 항목과 데이터를 저장하는 것 사이를 매핑하는 것을 제공합니다. </p> + +<pre class="brush: python">#best/models.py + +from django.db import models + +class Team(models.Model): + team_name = models.CharField(max_length=40) + + TEAM_LEVELS = ( + ('U09', 'Under 09s'), + ('U10', 'Under 10s'), + ('U11, 'Under 11s'), + ... #list our other teams + ) + team_level = models.CharField(max_length=3,choices=TEAM_LEVELS,default='U11') +</pre> + +<p>Django 모델은 데이터베이스 검색을 위한 간단한 쿼리를 제공 합니다. 다른 기준을 사용하여 한 번에 여러 필드와 일치시킬 수 있습니다. (예 : 대소 문자를 구분하지 않음,보다 큼, 등), 그리고 복잡한 명령문을 지원 할 수 있습니다 (예를 들어 당신이 "Fr"로 시작하거나 "al"로 끝나는 특별한 U11팀을 찾을 수 있습니다). </p> + +<p>두번째 코드 스니펫은 U09의 모든 팀을 보여주는 view function(요청 핸들러)을 보겠습니다. 이 경우 우리는 <code>team_level</code> 필드의 텍스트가 정확히 'U09'인 모든 레코드를 필터링하도록 지정합니다. ( 이 기준이 필드 이름과 일치 유형이 두 개의 밑줄로 구분 된 인수로 <code>filter()</code> 함수에 전달되는 방법을 아래에 기록하십시오. team_level__exact ).</p> + +<pre class="brush: python">#best/views.py + +from django.shortcuts import render +from .models import Team + +def youngest(request): + <strong>list_teams = Team.objects.filter(team_level__exact="U09")</strong> + context = {'youngest_teams': list_teams} + return render(request, 'best/index.html', context) +</pre> + +<dl> +</dl> + +<h3 id="Rendering_data">Rendering data</h3> + +<p>웹 프레임워크는 종종 템플릿 시스템을 제공합니다. 이것은 페이지가 생성될 때 데이터를 추가하기 위한 자리 표시 자를 사용하여 출력 문서 구조를 지정 할 수 있습니다. 템플릿들은 보통 HTML로 만들어지지만, 다른 형식의 문서로도 작성될 수 있습니다.</p> + +<p>웹 프레임워크는 보통 저장된 데이터를 다른 형식으로 쉽게 생성 할 수 있는,{{glossary("JSON")}}, {{glossary("XML")}}을 포함한, 틀을 제공합니다.</p> + +<p>예를들어, Django 템플릿 시스템은 구체화된 "double-handlebars" 구조 (예를 들어 <code>{</code><code>{ <em>variable_name</em> </code><code>}</code><code>}</code>)를 사용하도록 허용하는데, 이것은 페이지가 로딩될 때 뷰 함수의 값들로 대체될 수 있습니다. 템플릿 시스템은 또한 다양한 표현식을 지원하는데 (예를 들어 : <code>{% <em>expression</em> %}</code>), 템플리트가 템플리트에 전달 된 목록 값을 반복하는 것과 같은 간단한 조작을 수행 할 수 있습니다.</p> + +<div class="note"> +<p><strong>Note</strong>: 다른 대부분의 템플릿 시스템들은 비슷한 문법을 사용합니다, 예: Jinja2 (Python), handlebars (JavaScript), moustache (JavaScript), 등등.</p> +</div> + +<p>아래의 코드 스니펫은 그것이 어떻게 작동 하는지 보여줍니다. 이전 섹션에 사용한 "youngest team" 예제를 다시 보겠습니다, HTML 템플릿은 뷰에서 <code>youngest_teams</code>이라고 불리는 목록 변수를 전달 받습니다. HTML 골격 내에는 <code>youngest_teams</code>이 있는지 체크하는 표현식이 있고, 있다면 <code>for</code> 루프를 통해 반복문을 만드는 것을 볼 수 있습니다. 각 반복당 템플릿은 팀리스트에 있는 <code>team_name</code>을 출력해줍니다.</p> + +<pre class="brush: html">#best/templates/best/index.html + +<!DOCTYPE html> +<html lang="en"> +<body> + + {% if youngest_teams %} + <ul> + {% for team in youngest_teams %} + <li>\{\{ team.team_name \}\}</li> + {% endfor %} + </ul> +{% else %} + <p>No teams are available.</p> +{% endif %} + +</body> +</html> +</pre> + +<h2 id="웹프레임워크를_선택하는_방법">웹프레임워크를 선택하는 방법</h2> + +<p>여러분이 쓰고싶은 언어 대부분에 많은 웹 프레임워크들이 존재합니다(그중 보다 인기 있는 몇개의 프레임워크들을 다음 섹션에 나열합니다). 선택의 폭이 넓어지기 때문에 새로운 웹 애플리케이션을위한 최고의 출발점을 제공하는 프레임워크를 찾기가 어려울 수 있습니다.</p> + +<p>여러분의 선택에 영향을 줄 수 있는 요인은 다음과 같습니다.</p> + +<ul> + <li><strong>학습 노력 :</strong> 웹 프레임워크를 배우기 위한 노력은 당신이 얼마나 프로그래밍 언어에 익숙한지, 그 언어의 API가 일관성 있는지, 그 언어의 문서의 품질이 괜찮은지, 그리고 그 언어의 커뮤니티의 크기와 활동량에 따라 다릅니다. 만약 여러분이 아무런 프로그래밍 경험이 없다면, 장고를 고려해보세요(장고는 위의 기준에 맞는 가장 배우기 쉬운 프레임 워크입니다). 만약 여러분이 개발팀의 일원이며 이미 특정 웹프레임워크와 언어에 상당한 경험이 있다면, 그것에 충실하는 것이 좋습니다.</li> + <li><strong>생산성:</strong> 생산성은 프레임 워크에 익숙해지면 얼마나 빨리 새 기능을 만들 수 있는지 측정하는 척도이며 코드를 작성하고 유지 관리하는 노력(이전 기능이 손상된 상태에서 새 기능을 작성할 수 없기 때문에)을 모두 포함합니다. "학습 노력"에서 다루었던 요인들과 비슷한 많은 요인들이 생산성에 영향을 미칩니다. — 예를들어 문서, 커뮤니티, 프로그래밍 경험 등. — 다른 요인들: + <ul> + <li><em>프레임워크의 목적/출처</em>: 몇몇 웹 프레임워크들은 처음엔 특정 타입의 문제들을 풀기위해 만들어졌고, 여전히 비슷한 제약조건을 가진 웹앱을 만드는 데 좋습니다. 예를 들어 Django는 신문형식의 웹사이트 개발을 지원하기 위해 만들어졌기 때문에 블로그나 무언가를 출판하는 사이트들에 쓰기 좋습니다. 반대로 Flask는 모다 가벼운 무게의 프레임워크이고 임베디드 장치에서 실행되는 웹앱을 만드는데 좋습니다.</li> + <li><em>의도적인 vs 의도를 갖지 않는</em>: 의도적인 프레임워크는 특정유형의 문제를 풀기에 가장 좋은 방법으로 추천됩니다. 의도적인 프레임워크들은 일반적인 문제들을 풀려고 할 때 생산적으로 기능하기 때문에 여러분을 옳은 방향으로 이끌어주지만 유연성이 부족하기도 합니다.</li> + <li><em>배터리 포함 vs 직접 구매</em>: 몇몇 웹프레임워크는 개발자들이 "기본 적으로" 생각할 수 있는 모든 문제들을 해결하는 툴과 라이브러리를 포함합니다. 반면에 보다 가벼운 프레임웨크들은 웹개발자들이 직접 분리된 라이브러리들을 고르고 쓰기를 기대합니다. (Django는 전자의 예고 Flask는 아주 가벼운 프레임워크의 예입니다). 모든 것을 포함하는 프레임워크는 여러분이 필요한 모든 것을 이미 가지고 있고, 잘 병합/문서화되어있어 종종 시작하기에 더 쉽습니다. 그러나 더 작은 프레임 워크에 필요한 모든 것이 있다면 제약이 많은 환경에서 실행할 수 있으며 배우기에 더 작고 쉬울 것입니다. </li> + <li><em>프레임워크는 좋은 개발 관행을 장려 할 수 있습니다: </em>예를 들어, <br> + <a href="/en-US/docs/Web/Apps/Fundamentals/Modern_web_app_architecture/MVC_architecture">Model-View-Controller</a> 아키텍처를 권장하는 프레임 워크는 코드를 로직 함수로 분리하여 개발자에게 기대하지 않는 코드보다 더 유지 관리가 쉬운 코드가 생성됩니다. 비슷하게도, 프레임워크의 디자인은 테스트 하기 쉽고 재사용 하기 쉬운 코드를 만드는데에 큰 영향을 줄 수 있습니다.</li> + </ul> + </li> + <li><strong>프레임워크/프로그래밍 언어의 성능:</strong> 종종 "속도"는 선택의 중요한 한 요소가 되지 않습니다. 왜냐하면 Python과 같은 비교적 느린 런타임도 중간정도의 하드웨어에서 실행되는 중간 크기의 사이트에서 사용 하기에 "충분" 이상으로 좋기 때문입니다. 속도에 강점이 있는 언어들(예: C++ 또는 JavaScript)은 교육 비용이나 유지 비용에 의해 상쇄 될 수 있습니다.</li> + <li><strong>캐싱 지원:</strong> 웹 사이트가 더욱 성공적이 되면 당신은 웹 사이트에 액세스 할 때 수신하는 요청 수에 더 이상 대처할 수 없다는 것을 알게 될 것입니다. 이 시점에 캐싱 지원을 추가하는 것을 고려 할 수 있습니다. 캐싱은 웹 요청의 전체 또는 일부를 저장하여 후속 요청에서 다시 계산할 필요가 없도록하는 최적화 방법 입니다. 캐시된 요청에 대한 응답은 처음에 요청을 계산하는 것보다 훨씬 빠릅니다. 캐싱은 당신의 코드에 구현 하거나 서버에 구현 할 수 있습니다(<a href="https://en.wikipedia.org/wiki/Reverse_proxy">reverse proxy</a>를 참조하세요). 웹 프레임 워크는 캐시 할 수있는 컨텐츠를 정의하기 위해 서로 다른 레벨의 지원을 제공합니다.</li> + <li><strong>확장성:</strong> 웹 사이트가 환상적인 성공을하면 캐싱의 이점을 모두 활용하고 <em>수직 확장(</em>웹 애플리케이션을 보다 강력한 하드웨어에서 실행<em>)</em>의 한계에 도달 할 수 있습니다. 이 시점에서 일부 고객은 서버와 멀리 떨어져 있기 때문에 <em>수평 확장</em>(여러 웹 서버와 데이터베이스에 사이트를 분산 시켜서 부하를 공유)하거나 "지리적으로" 확장해야 할 수도 있습니다. 선택한 웹 프레임워크는 사이트 확장을 쉽게 하는지에 대해 큰 차이를 만들 수 있습니다.</li> + <li><strong>웹 보안:</strong> 어떤 웹 프레임워크는 일반적인 웹 공격 처리에 대한 더 나은 지원을 제공 합니다. 장고을 예를 들자면 사용자 입력에 들어간 모든 HTML 템플릿을 삭제하여 사용자가 작성한 JavaScript를 실행하지 못하게 합니다. 다른 프레임 워크도 유사한 보호 기능을 제공하지만 기본적으로 항상 활성화되어있는 것은 아닙니다.</li> +</ul> + +<p>라이센싱, 프레임워크가 활발하게 개발 중인지 여부 등 여러 가지 가능한 요소가 있습니다.</p> + +<p>프로그래밍을 처음 접하는 생초보라면 "학습 편의성"에 따라 프레임 워크를 선택하게 될 것입니다. 언어 자체의 "사용 편의성"외에도 고품질 문서 / 자습서 및 새로운 사용자를 돕는 활동적인 커뮤니티가 가장 소중한 리소스입니다. 우리는 <a href="https://www.djangoproject.com/">Django</a> (Python) 와 <a href="http://expressjs.com/">Express</a> (Node/JavaScript)를 선택하여 강의 후반에 예제를 작성했습니다. 배우기 쉽고 지원을 잘 받고 있기 때문입니다.</p> + +<div class="note"> +<p><strong>Note</strong>: <a href="https://www.djangoproject.com/">Django</a> (Python) 와 <a href="http://expressjs.com/">Express</a> (Node/JavaScript)의 메인 웹사이트로 가보십시오, 그리고 문서와 커뮤니티를 확인하십시오.</p> + +<ol> + <li>(위 링크들의) 메인 사이트를 둘러보기 + <ul> + <li>Documentation 메뉴에 링크들(Documentation, Guide, API Reference, Getting Started등)을 클릭해보십시오.</li> + <li>URL routing, templates, and databases/models등을 설정하는 주제들이 보이십니까?</li> + <li>해당 문서들은 명료하게 작성이 되어있습니까?</li> + </ul> + </li> + <li>각각의 사이트에서 mailing lists(해당 커뮤니티의 링크들을 통해서 접근할 수 있습니다)를 둘러보기 + <ul> + <li>지난 며칠동안 얼마나 많은 질문들이 올라왔습니까?</li> + <li>얼마나 많은 답변이 있습니까?</li> + <li>왕성한 활동을 보이는 커뮤니티를 갖고 있습니까?</li> + </ul> + </li> +</ol> +</div> + +<h2 id="A_few_good_web_frameworks">A few good web frameworks?</h2> + +<p>더 나아가, 몇몇 server-side 웹 프레임워크들에 대해 다루어보겠습니다.</p> + +<p>밑에 있는 server-side 프레임워크들은 이 글을 쓰는 시점에 인기 있는 프레임워크들 중 일부입니다. 몇이 프레임워크들은 생산성을 위해 필요한 것들을 갖추었습니다. — they are open source, are under active development, have enthusiastic communities creating documentation and helping users on discussion boards, and are used in large numbers of high-profile websites. 인터넷 검색을 통해 여기서 언급하지 않은 좋은 프레임워크들 찾을 수 있습니다. </p> + +<p><strong>Note</strong>: 여기에 기술되어있는 (일부) 내용들은 프레임워크의 사이트로부터 왔습니다!</p> + +<h3 id="Django_Python">Django (Python)</h3> + +<p><a href="https://www.djangoproject.com/">Django</a> is a high-level Python Web framework that encourages rapid development and clean, pragmatic design. Built by experienced developers, it takes care of much of the hassle of web development, so you can focus on writing your app without needing to reinvent the wheel. It’s free and open source.</p> + +<p>Django follows the "Batteries included" philosophy and provides almost everything most developers might want to do "out of the box". Because everything is included, it all works together, follows consistent design principles, and has extensive and up-to-date documentation. It is also fast, secure, and very scalable. Being based on Python, Django code is easy to read and to maintain.</p> + +<p>Popular sites using Django (from Django home page) include: Disqus, Instagram, Knight Foundation, MacArthur Foundation, Mozilla, National Geographic, Open Knowledge Foundation, Pinterest, Open Stack.</p> + +<h3 id="Flask_Python">Flask (Python)</h3> + +<p><a href="http://flask.pocoo.org/">Flask</a> is a microframework for Python. </p> + +<p>While minimalist, Flask can create serious websites out of the box. It contains a development server and debugger, and includes support for <a href="https://github.com/pallets/jinja">Jinja2</a> templating, secure cookies, <a href="https://en.wikipedia.org/wiki/Unit_testing">unit testing</a>, and <a href="http://www.restapitutorial.com/lessons/restfulresourcenaming.html">RESTful</a> request dispatching. It has good documentation and an active community. </p> + +<p>Flask has become extremely popular, particularly for developers who need to provide web services on small, resource-constrained systems (e.g. running a web server on a <a href="https://www.raspberrypi.org/">Raspberry Pi</a>, <a href="http://blogtarkin.com/drone-definitions-learning-the-drone-lingo/">Drone controllers</a>, etc.)</p> + +<h3 id="Express_Node.jsJavaScript">Express (Node.js/JavaScript)</h3> + +<p><a href="http://expressjs.com/">Express</a> is a fast, unopinionated, flexible and minimalist web framework for <a href="https://nodejs.org/en/">Node.js</a> (node is a browserless environment for running JavaScript). It provides a robust set of features for web and mobile applications and delivers useful HTTP utility methods and <a href="https://wiki.developer.mozilla.org/en-US/docs/Glossary/Middleware">middleware</a>.</p> + +<p>Express is extremely popular, partially because it eases the migration of client-side JavaScript web programmers into server-side development, and partially because it is resource-efficient (the underlying node environment uses lightweight multitasking within a thread rather than spawning separate processes for every new web request). </p> + +<p>Because Express is a minimalist web framework it does not incorporate every component that you might want to use (for example, database access and support for users and sessions are provided through independent libraries). There are many excellent independent components, but sometimes it can be hard to work out which is the best for a particular purpose! </p> + +<p>Many popular server-side and full stack frameworks (comprising both server and client-side frameworks) are based on Express, including <a href="http://feathersjs.com/">Feathers</a>, <a href="https://www.itemsapi.com/">ItemsAPI</a>, <a href="http://keystonejs.com/">KeystoneJS</a>, <a href="http://krakenjs.com/">Kraken</a>, <a href="http://loopback.io/">LoopBack</a>, <a href="http://mean.io/">MEAN</a>, and <a href="http://sailsjs.org/">Sails</a>.</p> + +<p>A lot of high profile companies use Express, including: Uber, Accenture, IBM, etc. (a list is provided <a href="http://expressjs.com/en/resources/companies-using-express.html">here</a>).</p> + +<h3 id="Ruby_on_Rails_Ruby">Ruby on Rails (Ruby)</h3> + +<p><a href="http://rubyonrails.org/">Rails</a> (usually referred to as "Ruby on Rails") is a web framework written for the Ruby programming language.</p> + +<p>Rails follows a very similar design philosophy to Django. Like Django it provides standard mechanisms for routing URLs, accessing data from a database, generating HTML from templates and formatting data as {{glossary("JSON")}} or {{glossary("XML")}}. It similarly encourages the use of design patterns like DRY ("dont repeat yourself" — write code only once if at all possible), MVC (model-view-controller) and a number of others.</p> + +<p>There are of course many differences due to specific design decisions and the nature of the languages.</p> + +<p>Rails has been used for high profile sites, including:<strong> </strong><a href="https://basecamp.com/">Basecamp</a>, <a href="https://github.com/">GitHub</a>, <a href="https://shopify.com/">Shopify</a>, <a href="https://airbnb.com/">Airbnb</a>, <a href="https://twitch.tv/">Twitch</a>, <a href="https://soundcloud.com/">SoundCloud</a>, <a href="https://hulu.com/">Hulu</a>, <a href="https://zendesk.com/">Zendesk</a>, <a href="https://square.com/">Square</a>, <a href="https://highrisehq.com/">Highrise</a>.</p> + +<h3 id="Laravel_PHP">Laravel (PHP)</h3> + +<p><a href="https://laravel.com/">Laravel</a> is a web application framework with expressive, elegant syntax. Laravel attempts to take the pain out of development by easing common tasks used in the majority of web projects, such as:</p> + +<ul> + <li><a href="https://laravel.com/docs/routing" rel="nofollow">Simple, fast routing engine</a>.</li> + <li><a href="https://laravel.com/docs/container" rel="nofollow">Powerful dependency injection container</a>.</li> + <li>Multiple back-ends for <a href="https://laravel.com/docs/session" rel="nofollow">session</a> and <a href="https://laravel.com/docs/cache" rel="nofollow">cache</a> storage.</li> + <li>Expressive, intuitive <a href="https://laravel.com/docs/eloquent" rel="nofollow">database ORM</a>.</li> + <li>Database agnostic <a href="https://laravel.com/docs/migrations" rel="nofollow">schema migrations</a>.</li> + <li><a href="https://laravel.com/docs/queues" rel="nofollow">Robust background job processing</a>.</li> + <li><a href="https://laravel.com/docs/broadcasting" rel="nofollow">Real-time event broadcasting</a>.</li> +</ul> + +<p>Laravel is accessible, yet powerful, providing tools needed for large, robust applications.</p> + +<h3 id="ASP.NET">ASP.NET</h3> + +<p><a href="http://www.asp.net/">ASP.NET</a> is an open source web framework developed by Microsoft for building modern web applications and services. With ASP.NET you can quickly create web sites based on HTML, CSS, and JavaScript, scale them for use by millions of users and easily add more complex capabilities like Web APIs, forms over data, or real time communications.</p> + +<p>One of the differentiators for ASP.NET is that it is built on the <a href="https://en.wikipedia.org/wiki/Common_Language_Runtime">Common Language Runtime</a> (CLR), allowing programmers to write ASP.NET code using any supported .NET language (C#, Visual Basic, etc.). Like many Microsoft products it benefits from excellent tools (often free), an active developer community, and well-written documentation.</p> + +<p>ASP.NET is used by Microsoft, Xbox.com, Stack Overflow, and many others.</p> + +<h3 id="Mojolicious_Perl">Mojolicious (Perl)</h3> + +<p><a href="http://mojolicious.org/">Mojolicious</a> is a next generation web framework for the Perl programming language.</p> + +<p>Back in the early days of the web, many people learned Perl because of a wonderful Perl library called <a href="https://metacpan.org/module/CGI">CGI</a>. It was simple enough to get started without knowing much about the language and powerful enough to keep you going. Mojolicious implements this idea using bleeding edge technologies.</p> + +<p>Some of the features provided by Mojolicious are: <strong>Real-time web framework</strong>, to easily grow single file prototypes into well-structured MVC web applications; RESTful routes, plugins, commands, Perl-ish templates, content negotiation, session management, form validation, testing framework, static file server, CGI/<a href="http://plackperl.org/">PSGI</a> detection, first class Unicode support; Full stack HTTP and WebSocket client/server implementation with IPv6, TLS, SNI, IDNA, HTTP/SOCKS5 proxy, UNIX domain socket, Comet (long polling), keep-alive, connection pooling, timeout, cookie, multipart and gzip compression support; JSON and HTML/XML parsers and generators with CSS selector support; Very clean, portable and object-oriented pure-Perl API with no hidden magic; Fresh code based upon years of experience, free and open source.</p> + +<h3 id="Spring_Boot_Java">Spring Boot (Java)</h3> + +<p><a href="https://spring.io/projects/spring-boot">Spring Boot</a> is one of a number of projects provided by <a href="http://spring.io/">Spring</a>. It is a good starting point for doing server-side web development using <a href="https://www.java.com/">Java</a>.</p> + +<p>Although definitely not the only framework based on <a href="https://www.java.com/">Java</a> it is easy to use to create stand-alone, production-grade Spring-based Applications that you can "just run". It is an opinionated view of the Spring platform and third-party libraries but allows to start with minimum fuss and configuration.</p> + +<p>It can be used for small problems but its strength is building larger scale applications that use a cloud approach. Usually multiple applications run in parallel talking to each other, with some providing user interaction and others just do back end work (e.g. accessing databases or other services). Load balancers help to ensure redundancy and reliability or allow geolocated handling of user requests to ensure responsiveness.</p> + +<h2 id="Summary">Summary</h2> + +<p>This article has shown that web frameworks can make it easier to develop and maintain server-side code. It has also provided a high level overview of a few popular frameworks, and discussed criteria for choosing a web application framework. You should now have at least an idea of how to choose a web framework for your own server-side development. If not, then don't worry — later on in the course we'll give you detailed tutorials on Django and Express to give you some experience of actually working with a web framework.</p> + +<p>For the next article in this module we'll change direction slightly and consider web security.</p> + +<p>{{PreviousMenuNext("Learn/Server-side/First_steps/Client-Server_overview", "Learn/Server-side/First_steps/Website_security", "Learn/Server-side/First_steps")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="https://wiki.developer.mozilla.org/en-US/docs/Learn/Server-side/First_steps/Introduction">Introduction to the server side</a></li> + <li><a href="https://wiki.developer.mozilla.org/en-US/docs/Learn/Server-side/First_steps/Client-Server_overview">Client-Server overview</a></li> + <li><a href="https://wiki.developer.mozilla.org/en-US/docs/Learn/Server-side/First_steps/Web_frameworks">Server-side web frameworks</a></li> + <li><a href="https://wiki.developer.mozilla.org/en-US/docs/Learn/Server-side/First_steps/Website_security">Website security</a></li> +</ul> diff --git a/files/ko/learn/server-side/first_steps/website_security/index.html b/files/ko/learn/server-side/first_steps/website_security/index.html new file mode 100644 index 0000000000..6fcc0fbb56 --- /dev/null +++ b/files/ko/learn/server-side/first_steps/website_security/index.html @@ -0,0 +1,164 @@ +--- +title: Website security +slug: Learn/Server-side/First_steps/Website_security +tags: + - 가이드 + - 보안 + - 서버측 프로그래밍 + - 웹 보안 + - 초보자 + - 학습 +translation_of: Learn/Server-side/First_steps/Website_security +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenu("Learn/Server-side/First_steps/Web_frameworks", "Learn/Server-side/First_steps")}}</div> + +<p class="summary">웹사이트 보안은 설계와 사용의 모든 측면에서 주의를 기울여야 한다. 이 글은 입문자용이므로 당신을 웹사이트 보안 전문가로 만들어주지는 않지만, 보안 위협 요소가 어디에서 발생하는지와, 가장 일반적인 공격으로부터 웹 응용 프로그램을 어떻게 강화할 수 있는지 이해하는데 도움을 줄 것이다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">사전 요구 지식 :</th> + <td>기본적인 컴퓨터 활용 능력.</td> + </tr> + <tr> + <th scope="row">학습목표 :</th> + <td> + <p>웹 애플리케이션 보안을 위협하는 가장 일반적인 요소들과, 해킹 당할 위험을 줄이는 방법을 이해한다.</p> + </td> + </tr> + </tbody> +</table> + +<h2 id="웹사이트_보안이란_무엇인가">웹사이트 보안이란 무엇인가?</h2> + +<p>인터넷은 위험한 곳이다! 구체적인 사례로, 우리는 정기적으로 웹사이트가 서비스 거부 공격으로 마비되거나, 홈페이지에 수정된 (그리고 종종 위해한) 정보가 게시된 소식을 듣는다. 또 다른 영향력이 큰 사례로, 수백만 개의 비밀번호, 이메일 주소, 신용카드 정보가 공용 도메인으로 유출되어, 웹사이트 사용자들에게 심리적 당혹감과 경제적인 위험을 유발한다.</p> + +<p>웹사이트 보안의 목적은 이러한 (또는 어떤) 종류의 공격을 방지하는 것이다. 딱딱하게 말하자면, <em>웹사이트 보안이란, 비승인된 접근, 사용, 수정, 파괴, 중단으로부터 웹사이트를 보호하는 행동 또는 실행을 가리킨다.</em></p> + +<p>웹사이트 보안을 효과적으로 하기 위해서는 웹사이트를 설계하는 과정의 전반에 걸쳐 노력을 기울여야 한다: 웹 애플리케이션에서, 웹 서버 설정에서, 비밀번호를 생성하고 재발급하는 정책에서, 클라이언트측 코드에서 말이다. 이 말이 보안에 필요한 많은 작업들을 당신이 직접 세세하게 해주어야 한다는 불길한 말로 들릴 수 있다. 하지만 다행스럽게도 서버측 웹 프레임워크를 사용한다면, 일반적인 보안 공격에 대해 이미 견고하고 잘 검증 된 방어 메커니즘이 "기본으로" 제공된다. 다른 공격들은 HTTPS를 활성화하는 등의 웹 서버 설정을 통해 방지할 수 있다. 마지막으로, 공개된 취약점 스캐너 도구를 사용하여 알려진 보안 실수들은 잡아낼 수 있을 것이다.</p> + +<p>이 글의 나머지 부분은 몇 가지 일반적인 보안 위협들과 사이트를 보호하기 위해 취할 수 있는 간단한 지침들을 제공한다.</p> + +<p><strong>Note</strong>: 입문자를 위한 주제이고, 웹사이트 보안에 대해 처음 생각해보는 이들을 돕기 위해 작성되었다. 완전하지 않으니 유의하길 바란다.</p> + +<h2 id="웹사이트_보안_위협들">웹사이트 보안 위협들</h2> + +<p>이 부분은 몇가지 일반적인 웹사이트 위협 요소들의 목록과 그 위협들을 어떻게 최소화할 수 있는지를 다룬다. 다음을 상기하며 읽자. 브라우저에서 전달되는 데이터를 신뢰하기만 하고 <em>충분한 피해망상을 가지지 않으면 </em>보안 위협 요소는 꼭 성공한다는 것을 상기해두자.</p> + +<h3 id="사이트_간_스크립팅_(Cross-Site_Scripting_XSS)">사이트 간 스크립팅 (Cross-Site Scripting, XSS)</h3> + +<p>XSS는 공격자가 클라이언트 측 스크립트를 웹 사이트에 삽입하여 다른 사용자의 부라우저에서 수행되게 하는 공격의 유형을 말한다. 삽입된 코드는 웹 사이트에서 피해 사용자의 브라우저로 전송이 됨으로 피해 사용자에게 의심받지 않는다. 따라서, 그 삽입된 코드는 피해 사용자의 사이트 권한 쿠키를 공격자에게 보내는 종류의 악성 작업을 수행할 수 있다. 그리고 그것을 전달 받은 공격자는 마치 피해 사용자인 것처럼 위장하여 사이트에 로그인하고 피해 사용자가 할 수 있는 모든 작업을 수행할 수 있다. 가령, 신용 카드 세부 정보에 접근하거나, 연락처 세부 정보를 확인하거나, 암호를 변경하는 작업 등을 수행할 수 있다.</p> + +<div class="note"> +<p><strong>Note</strong>: XSS 취약점은 전통적으로 다른 유형보다 일반적이었다.</p> +</div> + +<p>삽입된 스크립트를 브라우저에 반환하도록 사이트를 속이는 데에는 두 가지 주요 접근방법이 있다. 그것은 반사적 XSS 취약점과 지속적 XSS 취약점이다.</p> + +<ul> + <li>A <em>reflected</em> XSS vulnerability occurs when user content that is passed to the server is returned <em>immediately</em> and <em>unmodified</em> for display in the browser — any scripts in the original user content will be run when the new page is loaded!<br> + For example, consider a site search function where the search terms are encoded as URL parameters, and these terms are displayed along with the results. An attacker can construct a search link containing a malicious script as a parameter (e.g. <code>http://mysite.com?q=beer<script%20src="http://evilsite.com/tricky.js"></script></code>) and email it to another user. If the target user clicks this "interesting link", the script will be executed when the search results are displayed. As discussed above, this gives the attacker all the information they need to enter the site as the target user — potentially making purchases as the user or sharing their contact information.</li> + <li>A <em>persistent</em> XSS vulnerability is one where the malicious script is <em>stored</em> by the website and then later redisplayed unmodified for other users to unwittingly execute.<br> + For example, a discussion board that accepts comments containing unmodified HTML could store a malicious script from an attacker. When the comments are displayed the script is executed and can then send the attacker information required to access the user's account. This sort of attack is extremely popular and powerful, because the attacker doesn't have to have any direct engagement with the victims.<br> + <br> + While <code>POST</code> or <code>GET</code> data is the most common source of XSS vulnerabilities, any data from the browser is potentially vulnerable (including cookie data rendered by the browser, or user files that are uploaded and displayed).</li> +</ul> + +<p>The best defence against XSS vulnerabilities is to remove or disable any markup that can potentially contain instructions to run code. For HTML this includes tags like <code><script></code>, <code><object></code>, <code><embed></code>, and <code><link></code>.</p> + +<div> +<p>The process of modifying user data so that it can't be used to run scripts or otherwise affect the execution of server code is known as input sanitization. Many web frameworks automatically sanitize user input from HTML forms by default.</p> +</div> + +<h3 id="SQL_injection">SQL injection</h3> + +<p>SQL injection vulnerabilities enable malicious users to execute arbitrary SQL code on a database, allowing data to be accessed, modified or deleted irrespective of the user's permissions. A successful injection attack might spoof identities, create new identities with administration rights, access all data on the server, or destroy/modify the data to make it unusable.</p> + +<p>This vulnerability is present if user input that is passed to an underlying SQL statement can change the meaning of the statement. For example, consider the code below, which is intended to list all users with a particular name (<code>userName</code>) that has been supplied from an HTML form:</p> + +<pre class="brush: sql">statement = "SELECT * FROM users WHERE name = '" + <strong>userName</strong> + "';"</pre> + +<p>If the user enters a real name, this will work as intended. However a malicious user could completely change the behaviour of this SQL statement to the new statement below, simply by specifying the "<strong>bold</strong>" text below for the <code>userName</code>. The modified statement creates a valid SQL statement that deletes the <code>users</code> table and selects all data from the <code>userinfo</code> table (revealing the information of every user). This works because the first part of the injected text (<code>a';</code>) completes the original statement (' is the symbol to deliniate a string literal in SQL).</p> + +<pre class="brush: sql">SELECT * FROM users WHERE name = '<strong>a';DROP TABLE users; SELECT * FROM userinfo WHERE 't' = 't'</strong>; +</pre> + +<p>The way to avoid this sort of attack is to ensure that any user data that is passed to an SQL query cannot change the nature of the query. One way to do this is to <a href="https://en.wikipedia.org/wiki/Escape_character">escape</a> all the characters in the user input that have a special meaning in SQL.</p> + +<div class="note"> +<p><strong>Note</strong>: The SQL statement treats the ' character as the beginning and end of a string literal. By putting a backslash in front we "escape" the symbol (\'), and tell SQL to instead treat it as a character (just part of the string).</p> +</div> + +<p>In the statement below we escape the ' character. The SQL will now interpret the name as the whole string shown in bold (a very odd name indeed, but not harmful!)</p> + +<pre class="brush: sql">SELECT * FROM users WHERE name = '<strong>a\';DROP TABLE users; SELECT * FROM userinfo WHERE \'t\' = \'t'</strong>; + +</pre> + +<p>Web frameworks will often take care of this escaping for you. Django, for example, ensures that any user-data passed to querysets (model queries) is escaped.</p> + +<div class="note"> +<p><strong>Note</strong>: This section draws heavily on the information in <a href="https://en.wikipedia.org/wiki/SQL_injection">Wikipedia here</a>.</p> +</div> + +<h3 id="Cross_Site_Request_Forgery_(CSRF)">Cross Site Request Forgery (CSRF)</h3> + +<p>CSRF attacks allow a malicious user to execute actions using the credentials of another user without that user’s knowledge or consent.</p> + +<p>This type of attack is best explained by example. John is a malicious user who knows that a particular site allows logged-in users to send money to a specified account using an HTTP <code>POST</code> request that includes the account name and an amount. John constructs a form that includes his bank details and an amount of money as hidden fields, and emails it to other site users (with the <em>Submit</em> button disguised as a link to a "get rich quick" site).</p> + +<p>If a user clicks the submit button, an HTTP <code>POST</code> request will be sent to the server containing the transaction details and <em>any client-side cookies that the browser associates with the site</em> (adding associated site cookies to requests is normal browser behaviour). The server will check the cookies, and use them to determine whether or not the user is logged in and has permission to make the transaction.</p> + +<p>The result is that a<span style="line-height: 1.5;">ny user who clicks the <em>Submit</em> button while they are logged in to the trading site will make the transaction. John gets rich!</span></p> + +<div class="note"> +<p><strong>Note</strong>: The trick here is that John doesn't need to have access to the user's cookies (or access credentials) — the user's browser stores this information, and automatically includes it in all requests to the associated server.</p> +</div> + +<p>One way to prevent this type of attack is for the server to require that <code>POST</code> requests includes a user-specific site-generated secret (the secret would be supplied by the server when sending the web form used to make transfers). This approach prevents John from creating his own form because he would have to know the secret that the server is providing for the user. Even if he found out the secret and created a form for a particular user, he would no longer be able to use that same form to attack every user.</p> + +<p>Web frameworks often include such CSRF prevention mechanisms.</p> + +<h3 id="Other_threats">Other threats</h3> + +<p>Other common attacks/vulnerabilities include:</p> + +<ul> + <li><a href="https://www.owasp.org/index.php/Clickjacking">Clickjacking</a>. In this attack a malicious user hijacks clicks meant for a visible top level site and routes them to a hidden page beneath. This technique might be used, for example, to display a legitimate bank site but capture the login credentials into an invisible {{htmlelement("iframe")}} controlled by the attacker. It could alternatively be used to get the user to click a button on a visible site, but in doing so actually unwittingly click a completely different button. As a defence your site can prevent itself from being embedded in an iframe in another site by setting appropriate HTTP headers.</li> + <li><a href="/en-US/docs/Glossary/Distributed_Denial_of_Service">Denial of Service</a> (DoS). DoS is usually achieved by flooding a target site with spurious requests so that access to a site is disrupted for legitimate users. The requests may simply be numerous, or they may individually consume large amounts of resource (e.g. slow reads, uploading of large files, etc.) DoS defences usually work by identifying and blocking "bad" traffic while allowing legitimate messages through. These defences are typically within or before the web server (they are not part of the web application itself).</li> + <li><a href="https://en.wikipedia.org/wiki/Directory_traversal_attack">Directory Traversal</a>/File and disclosure. In this type of attack a malicious user attempts to access parts of the web server file system that they should not be able to access. This vulnerability occurs when the user is able to pass filenames that include file system navigation characters (e.g. <code>../../</code>). The solution is to sanitize input before using it.</li> + <li><a href="https://en.wikipedia.org/wiki/File_inclusion_vulnerability">File Inclusion</a>. In this attack a user is able to specify an "unintended" file for display or execution in data passed to the server. Once loaded this file might be executed on the web server or in the client-side (leading to an XSS attack). The solution is to sanitize input before using it.</li> + <li><a href="https://www.owasp.org/index.php/Command_Injection">Command Injection</a>. Command injection attacks allow a malicious user to execute arbitrary system commands on the host operating system. The solution is to sanitize user input before it might be used in system calls.</li> +</ul> + +<p>There are many more. For a comprehensive listing see <a href="https://en.wikipedia.org/wiki/Category:Web_security_exploits">Category:Web security exploits</a> (Wikipedia) and <a href="https://www.owasp.org/index.php/Category:Attack">Category:Attack</a> (Open Web Application Security Project).</p> + +<h2 id="A_few_key_messages">A few key messages</h2> + +<p>Almost all the exploits in the previous sections are successful when the web application trusts data from the browser. Whatever else you do to improve the security of your website, you should sanitize all user-originating data before it is displayed in the browser, used in SQL queries, or passed to an operating system or file system call.</p> + +<div class="warning"> +<p>Important: The single most important lesson you can learn about website security is to <strong>never trust data from the browser</strong>. This includes <code>GET</code> request data in URL parameters, <code>POST</code> data, HTTP headers and cookies, user-uploaded files, etc. Always check and sanitize all incoming data. Always assume the worst.</p> +</div> + +<p>A number of other concrete steps you can take are:</p> + +<ul> + <li>Use more effective password management. Encourage strong passwords that are changed regularly. Consider two-factor authentication for your site, so that in addition to a password the user must enter another authentication code (usually one that is delivered via some physical hardware that only the user will have, such as a code in an SMS sent to their phone).</li> + <li>Configure your web server to use <a href="/en-US/docs/Glossary/https">HTTPS</a> and <a href="/en-US/docs/Web/Security/HTTP_strict_transport_security">HTTP Strict Transport Security</a> (HSTS). HTTPS encrypts data sent between your client and server. This ensures that login credentials, cookies, <code>POST</code> data and header information are all much less available to attackers.</li> + <li>Keep track of the most popular threats (the <a href="/en-US/docs/">current OWASP list is here</a>) and address the most common vulnerabilities first.</li> + <li>Use <a href="https://www.owasp.org/index.php/Category:Vulnerability_Scanning_Tools">vulnerability scanning tools</a> to perform automated security testing on your site (later on, your very successful website may also find bugs by offering a bug bounty <a href="https://www.mozilla.org/en-US/security/bug-bounty/faq-webapp/">like Mozilla does here</a>).</li> + <li>Only store and display data that you need to. For example, if your users must store sensitive information like credit card details, only display enough of the card number that it can be identified by the user, and not enough that it can be copied by an attacker and used on another site. The most common pattern these days is to only display the last 4 digits of a credit card number.</li> +</ul> + +<p>Web frameworks can help mitigate many of the more common vulnerabilities.</p> + +<h2 id="Summary">Summary</h2> + +<p>This article has explained the concept of web security and some of the more common threats that your website should attempt to protect against. Most importantly, you should understand that a web application cannot trust any data from the web browser! All user data should be sanitized before it is displayed, or used in SQL queries or file system calls.</p> + +<p>That's the end of <a href="/en-US/docs/Learn/Server-side/First_steps">this module</a>, covering your first steps in server-side website programming. We hope you've enjoyed learning the fundamental concepts, and you're now ready to select a Web Framework and start programming.</p> + +<p>{{PreviousMenu("Learn/Server-side/First_steps/Web_frameworks", "Learn/Server-side/First_steps")}}</p> diff --git a/files/ko/learn/server-side/index.html b/files/ko/learn/server-side/index.html new file mode 100644 index 0000000000..4cdb1454cd --- /dev/null +++ b/files/ko/learn/server-side/index.html @@ -0,0 +1,57 @@ +--- +title: Server-side website programming +slug: Learn/Server-side +tags: + - Beginner + - CodingScripting + - Intro + - Landing + - Learn + - Server + - Server-side programming + - Topic +translation_of: Learn/Server-side +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">The <strong><em>Dynamic Websites(동적 웹사이트) </em></strong>–<em><strong> Server-side programming(서버-사이드 프로그래밍)</strong></em> 에 대한 주제는 동적 웹사이트를 생성하는 방법을 보여주는 과목(module) 시리즈이다; (Dynamic Websites: HTTP 요구(requests)에 응답하여 요구에 맞는 정보를 전달하는 웹사이트) 각 과목들은 서버-사이드 프로그래밍의 포괄적인 소개를 제공한다. 기본적인 어플리케이션들을 생성하기 위한 Django (Python) 와Express (Node.js/JavaScript) 같은 웹 프레임워크를 사용하는 방법에 대한 초보자 레벨(beginner level)의 가이드도 포함한다.</p> + +<p>대부분의 주요 웹사이트들은 요구에 따라 동적으로 다른 데이터들을 보여주기 위해 여러 종류의 서버-사이드 기술을 사용한다. 예를 들어, Amazon에서 이용가능한 물품들이 얼마나 많을까? 그리고 Facebok에 얼마나 많은 게시글이 있을까? 를 상상해보자. 완전히 다른 static pages(정적 페이지)를 사용하여 이런 것들을 보여주는 것은 완전히 비효율적이다, 그래서 대신에 그런 정적인 템플릿(<a href="/en-US/docs/Learn/HTML">HTML</a>, <a href="/en-US/docs/Learn/CSS">CSS</a>, <a href="/en-US/docs/Learn/JavaScript">JavaScript</a> 를 사용하여 구성된 템플릿)을 보여준 다음, 필요할 때마다, 템플릿 안에 보이는 데이터들을 동적으로 업데이트한다. 예) 당신이 Amazon에서 다른 물품을 보고 싶어할 때 물품만 다른 것으로 업데이트한다.</p> + +<p>현대의 웹 개발에서는, 서버-사이드 개발에 대해 배우는 것을 매우 추천한다.</p> + +<h2 id="Learning_pathway(학습_경로)">Learning pathway(학습 경로)</h2> + +<p>서버-사이드 프로그래밍을 시작하는 것은 보통 클라이언트-사이드(Client-side) 개발보다 더 쉽다. 왜냐하면, 동적 웹사이트는 비슷한 작업들을 많이 수행하는 경향이 있기 때문이다. (데이터베이스에서 데이터를 검색하고 페이지에 보여주는 것, 유저가 입력한 데이터터가 유효한 지 확인하고 데이터 베이스에 저장하는 것, 로그인한 유저의 권환을 체크하는 것 등) 그리고 이런 작업들과 다른 일반적인 웹 서버 기능을 쉽게 해주는 웹 프레임워크가 있기 때문이다.</p> + +<p>기본적인 프로그래밍 개념에 대한 지식 (또는 특정한 프로그래밍 언어에 대한 지식) 은 유용하나, 필수는 아니다. 비슷하게, 클라이언트-사이드 코딩에 대한 전문지식이 요구되지 않는다, 그러나 기본적인 지식은 클라이언트-사이드 웹 "프론트 엔드(Front End)"를 생성하는 개발자와 일 하는데 도움이 될 것이다.</p> + +<p>"웹을 작동하는 방법"을 이해할 필요가 있다. 다음 주제들을 먼저 읽는 것을 추천한다.</p> + +<ul> + <li><a href="/ko/docs/Learn/Common_questions/What_is_a_web_server">What is a web server(웹서버는 무엇인가)</a></li> + <li><a href="/ko/docs/Learn/Common_questions/What_software_do_I_need">What software do I need to build a website?(웹사이트를 만들기 위해 필요한 소프트웨어는 무엇인가)</a></li> + <li><a href="/ko/docs/Learn/Common_questions/Upload_files_to_a_web_server">How do you upload files to a web server?(웹 서버에 파일을 업로드하는 방법은 무엇인가)</a></li> +</ul> + +<p>이런 기본적인 이해를 통해, 이 섹션의 과목들을 공부할 준비가 될 것이다.</p> + +<h2 id="Modules(과목)">Modules(과목)</h2> + +<p>이번 주제에는 다음의 과목들을 포함하고 있다. 우선 첫번째 과목을 시작해야한다. 그 후에 두 개의 과목들 중 하나를 선택해 나아가야한다. 두 개의 과목은 가장 대중적인 서버-사이드 언어와 그에 맞는 적절한 웹 프레임워크를 사용하는 방법을 보여준다.</p> + +<dl> + <dt><a href="/ko/docs/Learn/Server-side/First_steps">Server-side website programming first steps(서버-사이드 웹사이트 프로그래밍의 첫 단계)</a></dt> + <dd>이 과목은 서버 기술 문외한을 위한 서버-사이드 웹사이트 프로그래밍에 대한 정보를 제공한다. 또한, 서버-사이드 프로그래밍에 대한 근본적인 질문에 대한 답을 포함하고 있다. (그 질문은 서버가 무엇인지, 클라이언트-프로그래밍과 어떻게 다른 지, 서버가 왜 그렇게 유용한 지에 대한 것이다.) 그리고 몇몇의 더 대중적인 서버-사이드 웹 프레임워크에 대한 개요와 당신의 사이트에 가장 적합한 것을 선택하는 방법에 대한 가이드도 있다. 마지막으로, 웹 서버 보안에 대한 기본적인 섹션도 제공한다.</dd> + <dt><a href="/ko/docs/Learn/Server-side/Django">Django Web Framework (Python)</a></dt> + <dd>Django는 매우 대중적이고 Python으로 쓰여진 매우 중요한 서버-사이드 웹 프레임워크이다. 이 과목은 Django가 좋은 웹 서버 프레임워크인 이유, 개발 환경을 구축하는 방법, 그리고 Django로 일반적인 업무를 수행하는 방법을 설명해준다.</dd> + <dt><a href="/ko/docs/Learn/Server-side/Express_Nodejs">Express Web Framework (Node.js/JavaScript)</a></dt> + <dd>Express는 JavaScript로 쓰여진 대중적인 웹 프레임워크이며, node.js 런 타임 환경에서 호스트된다. 이 과목은 이 프레임 워크의 주요 장점, 개발 환경을 구축하는 법, 일반적인 웹 개발과 배치(deployment) 작업을 수행하는 법에 대해 설명해준다.</dd> +</dl> + +<h2 id="다른_주제">다른 주제</h2> + +<dl> + <dt><a href="/ko/docs/Learn/Server-side/Node_server_without_framework">Node server without framework(프레임워크 없는 노드 서버)</a></dt> + <dd>이 글은 프레임워크를 사용하고 싶지 않는 사람들을 위해, 순수한 Node.js로 구성된 단순한 정적 파일 서버를 제공한다.</dd> +</dl> diff --git a/files/ko/learn/skills/index.html b/files/ko/learn/skills/index.html new file mode 100644 index 0000000000..a73870b4a9 --- /dev/null +++ b/files/ko/learn/skills/index.html @@ -0,0 +1,21 @@ +--- +title: 스킬 +slug: Learn/Skills +tags: + - Index +translation_of: Learn +--- +<p>여러분은 웹에 대하여 학습할 때 수 많은 스킬들을 선택해야 합니다. <a href="https://webmaker.org/en-US" rel="external">WebMaker</a>는 초심자들이 기초를 학습하는 로드맵인 <a href="https://webmaker.org/en-US/literacy" rel="external">Web Literacy Map</a>이라는 기본 스킬들의 목록을 정의합니다. 여기 MDN에서는 웹사이트를 제작하는데 필요한 역량에 초점을 맞추고, 모든 스킬 레벨에 대한 학습을 제공합니다:</p> + +<dl> + <dt><a href="/en-US/docs/Learn/Web_Mechanics">Web Mechanics</a></dt> + <dd>웹 생태계를 이해한다</dd> + <dt><a href="/en-US/docs/Learn/Infrastructure">Infrastructure</a></dt> + <dd>웹의 기술적 스택을 이해한다</dd> + <dt><a href="/en-US/docs/Learn/Coding-Scripting">Coding/Scripting</a></dt> + <dd>상호적인 웹 경험(Web experience)를 만든다.</dd> + <dt><a href="/en-US/docs/Learn/Design_and_Accessibility">Design and Accessibility</a></dt> + <dd>웹 리소스를 이용하여 모두와 효과적으로 의사소통한다</dd> + <dt><a href="/en-US/docs/Learn/Composing_for_the_web">Composing for the web</a></dt> + <dd>웹 콘텐츠를 만들고 관장한다</dd> +</dl> diff --git a/files/ko/learn/tools_and_testing/client-side_javascript_frameworks/index.html b/files/ko/learn/tools_and_testing/client-side_javascript_frameworks/index.html new file mode 100644 index 0000000000..34a443990a --- /dev/null +++ b/files/ko/learn/tools_and_testing/client-side_javascript_frameworks/index.html @@ -0,0 +1,165 @@ +--- +title: Understanding client-side JavaScript frameworks +slug: Learn/Tools_and_testing/Client-side_JavaScript_frameworks +translation_of: Learn/Tools_and_testing/Client-side_JavaScript_frameworks +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">자바스크립트 프레임워크는 최신 프론트엔드 웹 개발의 필수 부분으로, 개발자에게 확장 가능한 대화형 웹 응용 프로그램을 구축하기 위한 검증된 도구를 제공합니다. 많은 현대 기업들은 프레임워크를 도구화(tooling)의 표준 부분으로 사용하기때문에, 프론트엔드 개발에는 이제 프레임워크 경험이 필요합니다.</p> + +<p class="summary">프론트엔드 개발자 지망생으로서 프레임워크를 배울 때 시작해야 할 부분을 알기가 어려울 수 있습니다. 선택할 수 있는 프레임워크가 너무 많고, 새로운 프레임워크는 항상 나타나고,대부분 유사한 방식으로 작동하지만 다른 일을 합니다. 때문에 프레임워크를 사용할 때 주의해야 할 몇 가지 사항이 있습니다.</p> + +<p class="summary">이 글에서는 프레임워크를 배우는데 도움이되는 편안한 출발점을 제공하고자 합니다. 우리는 React/ReactDOM, Vue, 또는 그외 특정 프레임워크에 대해 알아야 할 모든 것을 철저하게 가르치려는것이 아닙니다. 프레임워크 자체 문서들 및 다른 리소스들이 이미 철저하게 가르쳐주고 있습니다. 대신 우리는 다음과 같은, 보다 근본적인 질문에 답하고 지원하려고 합니다.</p> + +<ul> + <li class="summary">왜 프레임워크를 사용해야 하나요? 그들이 어떤 문제를 해결하나요?</li> + <li class="summary">프레임워크를 선택할 때 어떤 질문을 해야 하나요? 프레임워크를 사용해야 하나요?</li> + <li class="summary">프레임워크에는 어떤 기능이 있나요? 그것들은 일반적으로 어떻게 작동하고, 이러한 기능에 대한 프레임워크에 구현은 어떻게 다른가요?</li> + <li class="summary">"vanilla" 자바스크립트 또는 HTML과 어떤 관련이 있나요?</li> +</ul> + +<p class="summary">그 후에, 우리는 몇 가지 다른 프레임워크 선택의 핵심을 다루는 튜토리얼을 제공할 것입니다. 이는 더 심도있게 학습하기에 충분한 맥락과 친숙함을 제공해줄겁니다. 우리는 여러분이 앞으로 나아가 접근성과 같은 웹 플랫폼의 근본적인 모범 사례를 잊지 않는 실용적인 방법으로 프레임워크에 대해 배우고 발전시키기를 바랍니다.</p> + +<p class="summary"><strong><a href="/ko/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Introduction">"클라이언트 사이드 프레임워크 소개"문서로 지금 시작하세요!</a></strong></p> + +<h2 id="전제조건">전제조건</h2> + +<p>클라이언트 사이드 프레임워크를 배우기 전에 <a href="/ko/docs/Learn/HTML">HTML</a>, <a href="/ko/docs/Learn/CSS">CSS</a>, <a href="/ko/docs/Learn/JavaScript">JavaScript</a> 와 같은 핵심 웹 언어의 기초를 익혀야 합니다.</p> + +<p>결과적으로 코드는 더욱 풍부해지고 전문적이게 될 것이며, 프레임워크가 구축하고 있는 근본적인 웹 플랫폼 기능을 이해한다면 보다 확실하게 문제를 해결할 수 있을 겁니다.</p> + +<div class="in-page-callout webdev"> +<h3 id="프론트_개발자가_되고_싶으신가요">프론트 개발자가 되고 싶으신가요?</h3> + +<p>목표를 달성하는데 필요한 모든 필수 정보가 포함 된 과정을 구성했습니다.</p> + +<p><a class="cta primary" href="/docs/Learn/Front-end_web_developer">시작하기</a></p> +</div> + +<h2 id="입문_가이드">입문 가이드</h2> + +<dl> + <dt><a href="/ko/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Introduction">1. 클라이언트 사이드 프레임워크 소개</a></dt> + <dd>우리는 이 영역에 대한 일반적인 개요로 프레임워크를 살펴 볼겁니다. 자바스크립트와 프레임워크의 간략한 역사, 프레임워크가 왜 존재하는지와 그들이 우리에게 무엇을 제공하는지, 학습을 프레임워크를 어떻게 선택할지 생각하는 방법, 클라이언트 사이드 프레임워크에 대한 어떤 대안이 있는지 등이 해당합니다.</dd> + <dt><a href="/ko/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Main_features">2. 프레임워크 주요 기능</a></dt> + <dd>각 주요 자바스크립트 프레임워크는 DOM 업데이트, 브라우저 이벤트 처리, 즐거운 개발 경험에 대해 다양한 접근 방식을 갖고 있습니다. 이 글에서는 "4대" 프레임워크의 주요 기능을 살펴보고 프레임워크가 높은 수준에서 작동하는 방식과 프레임워크의 차이점을 살펴봅니다.</dd> +</dl> + +<h2 id="리액트_튜토리얼">리액트 튜토리얼</h2> + +<div class="blockIndicator note"> +<p><strong>참조</strong>: React/ReactDOM 16.13.1과 create-react-app 3.4.1. 을 사용하여 2020년 5월에 마지막으로 테스트된 튜토리얼입니다.</p> + +<p>우리의 버전에 대해 여러분의 코드를 확인해야 하는 경우, 우리의 <a href="https://github.com/mdn/todo-react">todo-react repository</a>에서 샘플 React app 코드의 완성된 버전을 볼 수 있습니다. 라이브 버전을 실행하려면<a href="https://mdn.github.io/todo-react-build/">https://mdn.github.io/todo-react-build/</a>을 참조하세요.</p> +</div> + +<dl> + <dt><a href="/ko/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_getting_started">1. React 시작하기</a></dt> + <dd>이 글은 리액트에 대한 첫걸음입니다. 우리는 리액트의 배경과 사용 사례에 대한 약간의 세부 사항을 학습합니다. 우리 컴퓨터 로컬에서 기본적인 리액트 툴체인을 설정하고, 간단한 스타터 앱을 만들어 리액트가 어떻게 작동하는지 배웁니다.</dd> + <dt><a href="/ko/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_todo_list_beginning">2. React todo list 시작하기</a></dt> + <dd>우리가 React에서 개념 증명(proof-of-concept)을 작성하는 임무를 맡았다고 가정 해 봅시다. 사용자가 작업하려는 과제(task)를 추가, 수정, 삭제 혹은 그것들을 삭제하는 대신 완료된 것으로 표시할 수 있는 앱입니다. 이 글에서는 기본 앱 컴포넌트 구조와 스타일을 배치하는 과정, 각각의 컴포넌트를 정의하고 상호작용하는 방법을 설명합니다.</dd> + <dt><a href="/ko/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_components">3. React app 컴포넌트 세분화</a></dt> + <dd>이 시점에서 우리의 앱은 단일체(monolith)입니다. 우리는 이것을 관리 가능하고 설명적인 컴포넌트들로 분리해야 합니다. React에는 컴포넌트와 컴포넌트가 아닌것에 대한 엄격한 규칙이 없습니다. 그것은 사용자에게 달려있습니다. 이 글에서는 앱을 컴포넌트로 분해하는 합리적인 방법을 보여줍니다.</dd> + <dt><a href="/ko/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_interactivity_events_state">4. React 상호작용(interactivity): Events 와 state</a></dt> + <dd>컴포넌트 구성이 완성되면 완전한 정적 UI 에서 실제로 상호작용하고 변화시킬 수 있는 UI로 앱을 업데이트할 차례입니다. 이 글에서는 이벤트와 state에 대해 자세히 알아봅니다.</dd> + <dt><a href="/ko/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_interactivity_filtering_conditional_rendering">5. React 상호작용(interactivity): 수정, 필터링, 조건부 렌더링</a></dt> + <dd>리액트 여정이 끝날 무렵(적어도 현재로서는) Todo list 앱의 주요 기능 영역에 마무리 작업을 추가합니다. 여기서는 기존 과제(task)를 편집할 수 있도록 하고, 완료된 과제와 완료되지 않은 과제 모두 필터링 하는 작업이 포함됩니다. 또한 도중에 조건부 UI 렌더링도 살펴보겠습니다.</dd> + <dt><a href="/ko/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_accessibility">6. React 접근성(Accessibility)</a></dt> + <dd>이 글에서는 React의 포커스 관리를 포함하여 접근성에 관점을 맞출것입니다. 키보드 전용 및 스크린 리더기 사용자 모두에게 유용성을 개선하고 혼동을 줄일 수 있습니다.</dd> + <dt><a href="/ko/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_resources">7. React 리소스(resources)</a></dt> + <dd>우리의 마지막 글은 학습을 계속하기 위해 사용할 수 있는 React 리소스 목록을 제공합니다.</dd> +</dl> + +<h2 id="Ember_tutorials">Ember tutorials</h2> + +<div class="blockIndicator note"> +<p><strong>참조</strong>: Ember/Ember CLI 3.18.0을 사용하여 2020년 5월에 마지막으로 테스트된 튜토리얼입니다.</p> + +<p>우리의 버전에 대해 여러분의 코드를 확인해야 하는 경우, 우리의 <a href="https://github.com/NullVoxPopuli/ember-todomvc-tutorial/tree/master/steps/00-finished-todomvc/todomvc">ember-todomvc-tutorial repository</a>에서 샘플 Ember app 코드의 완성된 버전을 볼 수 있습니다. 라이브 버전을 실행하려면 <a href="https://nullvoxpopuli.github.io/ember-todomvc-tutorial/">https://nullvoxpopuli.github.io/ember-todomvc-tutorial/</a> 을 참조하세요. (여기에는 튜토리얼에서 다루지 않은 몇 가지 기능도 포함됩니다.)</p> +</div> + +<dl> + <dt><a href="/ko/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_getting_started">1. Ember 시작하기</a></dt> + <dd>첫 번째 Ember 글에서는 Ember 의 작동방식과 유용한 기능에 대해 살펴봅니다. 로컬에 Ember 툴체인을 설치하고, 샘플 앱을 만들어 개발 준비를 위한 초기 설정을 수행합니다.</dd> + <dt><a href="/ko/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_structure_componentization">2. Ember app 구조와 컴포넌트화</a></dt> + <dd>이 글에서는 TodoMVC Ember app의 구조를 설계하는 방법에 대해 알아봅니다. HTML을 추가하고, HTML 구조를 컴포넌트로 나눕니다.</dd> + <dt><a href="/ko/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_interactivity_events_state">3. Ember 상호작용(interactivity): Events, classes, state</a></dt> + <dd>이제 앱에 상호작용하는 기능을 추가하여 새로운 할일(todo) 항목을 추가하고 표시할 수 있습니다. 그 과정에서 Ember 이벤트를 사용하는 방법을 살펴보겠습니다. 상호작용하는 기능을 제어하기 위해 자바스크립트 코드를 포함하는 컴포넌트 클래스를 만들고, 앱의 데이터 상태(state)를 추적하는 서비스를 설정합니다.</dd> + <dt><a href="/ko/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_conditional_footer">4. Ember 상호작용: 푸터 기능, 조건부 렌더링</a></dt> + <dd>이제 앱에서 푸터 기능을 시작할 차례입니다. 아직 완료하지 않은 할일(todo) 항목의 수를 카운트하고, 완료된 할일(체크표시한 체크박스)에 스타일을 올바르게 적용합니다. 또한 "Clear completed" 버튼을 연결합니다. 이 과정에서 템플릿에서 조건부 렌더링을 사용하는 방법을 배웁니다.</dd> + <dt><a href="/ko/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_routing">5. Ember 라우팅</a></dt> + <dd>이 글에서는 라우팅 또는 URL기반 필터링에 대해 설명합니다. 이를 사용하여 todo의 세 가지 뷰("All", "Active", "Completed")를 고유한 URL로 제공합니다.</dd> + <dt><a href="/ko/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_resources">6. Ember 리소스와 문제해결</a></dt> + <dd>마지막 Ember 글은 학습을 진행하는데 사용할 수 있는 리소스 목록, 유용한 문제 해결(troubleshooting)에 관한 내용, 그외 정보를 제공합니다.</dd> +</dl> + +<h2 id="Vue_tutorials">Vue tutorials</h2> + +<div class="blockIndicator note"> +<p><strong>참조</strong>: Vue 2.6.11을 사용하여 2020년 5월에 마지막으로 테스트한 튜토리얼입니다.</p> + +<p>우리의 버전에 대해 여러분의 코드를 확인해야 하는 경우, 우리의 <a href="https://github.com/mdn/todo-vue">todo-vue repository</a>에서 샘플 Vue app 코드의 완성된 버전을 볼 수 있습니다. 라이브 버전을 실행하려면 <a href="https://mdn.github.io/todo-vue/dist/">https://mdn.github.io/todo-vue/dist/</a> 를 참조하세요.</p> +</div> + +<dl> + <dt><a href="/ko/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_getting_started">1. Vue 시작하기</a></dt> + <dd>이제 세 번째 프레임워크 뷰를 소개합니다. 이 글에서는 Vue의 배경을 약간 살펴보고, 설치 방법과 새 프로젝트를 만드는 방법에 대해 알아봅니다. 전체 프로젝트의 HLS(high-level structure) 와 각각의 컴포넌트를 공부합니다. 또한, 프로젝트를 로컬에서 실행하는 방법과 예제 작성을 시작할 준비를 합니다.</dd> + <dt><a href="/ko/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_first_component">2. 첫 번째 Vue 컴포넌트 만들기</a></dt> + <dd>이제 Vue에 대해 자세히 살펴보고 우리만의 커스텀 컴포넌트를 만들겠습니다. Todo list의 각 항목을 나타내는 컴포넌트를 만드는 것으로 시작합니다. 그 과정에서, 다른 컴포넌트 내에서 컴포넌트를 호출하고, props(properties)를 통해 데이터를 전달하고 데이터 상태를 저장하는 등 중요한 개념을 학습합니다.</dd> + <dt><a href="/ko/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_rendering_lists">3. Vue 컴포넌트 리스트 렌더링</a></dt> + <dd><span class="author-d-1gg9uz65z1iz85zgdz68zmqkz84zo2qoxwoxz78zz83zz84zz69z2z80zgwxsgnz83zfkt5e5tz70zz68zmsnjz122zz71z">이 시점에서 우리는 충분히 잘 작동하는 컴포넌트를 얻었습니다. 이제 앱에 여러 <code>ToDoItem</code> 컴포넌트를 추가할 준비가 되었습니다. 이 글에서는 <code>App.vue</code> 컴포넌트에 todo 항목 데이터 셋을 추가하는 방법을 살펴보고, <code>v-for</code> 지시문(directive)을 사용하여 <code>ToDoItem</code> 컴포넌트를 반복하여 출력합니다. </span></dd> + <dt><a href="/ko/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_methods_events_models">4. 새로운 todo form추가: Vue events, methods, models</a></dt> + <dd>이제 샘플 데이터와 각 비트의 데이터를 가져와서 앱의 <code>ToDoItem</code> 내에 렌더링하는 루프가 준비되었습니다. 다음으로 필요한 것은 사용자가 todo 항목을 앱에 입력할 수 있게 하는 기능입니다. 이를 위해 text <code><input></code>, 데이터가 제출될 때 발생하는 이벤트, 데이터 제출 시 데이터를 추가하고 목록을 다시 렌더링하기 위한 방법, 데이터를 제어하는 모델이 필요합니다. 이것이 이 글에서 다룰 내용입니다.</dd> + <dt><a href="/ko/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_styling">5. Styling Vue components with CSS</a></dt> + <dd>마침내 우리 앱이 좀 더 멋지게 보입니다. 이 글에서는 CSS를 사용하여 Vue 컴포넌트를 스타일링하는 다양한 방법을 살펴봅니다.</dd> + <dt><a href="/ko/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_computed_properties">6. Vue computed properties 사용하기</a></dt> + <dd>이 글에서는 computed properties 라고 불리는 Vue 기능을 사용하여 완료된 todo 항목 수를 표시하는 카운터를 추가합니다. 이들은 메서드와 유사하게 작동하지만 종속성 중 하나가 변경될 때만 다시 실행됩니다.</dd> + <dt><a href="/ko/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_conditional_rendering">7. Vue 조건부 렌더링: 이미 존재하는 todo 항목 편집</a></dt> + <dd>이제 우리가 아직 놓치고 있는 주요 기능 중 한 기능의 주요한 부분 중 하나를 추가 할 차례입니다. 이를 위해 Vue의 조건부 렌더링 기능 <code>v-if</code> 와 <code>v-else</code> 를 활용하여, 이미 존재하는 todo 항목 view 와 todo 항목 레이블을 업데이트 할 수 있는 편집 view 간에 전환할 수 있습니다. 또한 todo 항목들을 삭제하는 기능을 추가하는 방법도 살펴봅니다.</dd> + <dt><a href="/ko/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_refs_focus_management">8. Vue refs를 통한 포커스 관리</a></dt> + <dd>이제 거의 다 만들었습니다. 마지막으로 살펴볼 기능은 포커스 관리와 앱의 키보드 접근성을 향상시키는 방법입니다. Vue refs를 사용하여 이를 처리하는 방법을 살펴보겠습니다. ref는 가상 DOM 아래의 기본 DOM 노드에 직접 접근하거나 한 컴포넌트에서 하위 컴포넌트의 내부 DOM 구조로 직접 접근할 수 있는 고급 기능입니다.</dd> + <dt><a href="/ko/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_resources">9. Vue resources</a></dt> + <dd>이제 Vue에 대한 학습을 마무리 할 것입니다. 학습을 진행하는데 사용할 수 있는 리소스 목록과 유용한 팁이 있습니다.</dd> +</dl> + +<h2 id="Svelte_tutorials">Svelte tutorials</h2> + +<div class="blockIndicator note"> +<p><strong>참조</strong>: Svelte 3.24.1 을 사용하여 2020년 8월에 마지막으로 테스트된 튜토리얼입니다.</p> + +<p>코드를 우리 버전과 비교하여 확인해야 하는 경우, <a href="https://github.com/opensas/mdn-svelte-tutorial">mdn-svelte-tutorial</a> repo에서 각각의 문서 뒤에 있어야 하는 샘플 Svelte 앱 코드의 완성된 버전을 볼 수 있습니다. 라이브 버전을 실행하려면 Svelte REPL 을 참조하세요 <a class="external external-icon" href="https://svelte.dev/repl/378dd79e0dfe4486a8f10823f3813190?version=3.23.2" rel="noopener">https://svelte.dev/repl/378dd79e0dfe4486a8f10823f3813190?version=3.23.2</a>.</p> +</div> + +<dl> + <dt><a href="/ko/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_getting_started">1. Svelte 시작하기</a></dt> + <dd>이 문서에서는 <a class="external external-icon" href="https://svelte.dev/" rel="noopener">Svelte framework</a>에 대한 간략한 소개를 제공합니다. Svelte의 작동 방식과 지금까지 살펴본 나머지 프레임워크 및 도구와 차별화되는 점을 살펴보겠습니다. 그 다음 개발 환경 구성하기, 샘플 앱 만들기, 프로젝트 구조 이해하기, 로컬에서 실행하기와 프로덕션 용으로 빌드하는 방법을 알아보겠습니다.</dd> + <dt><a href="/ko/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_Todo_list_beginning">2. Svelte Todo list app 시작하기</a> </dt> + <dd>이제 Svelte가 작동하는 방식에 대한 기본적인 이해를 마쳤으므로, 예제 앱(todo list) 빌드를 시작하겠습니다. 이 문서에서는 먼저 앱에서 구현해야할 기능을 살펴보고, 그 다음 <code>Todos.svelte</code> 컴포넌트를 만들어 정적 마크업과 스타일을 배치합니다. 그리고 To-Do list 앱 기능 개발을 시작할 준비를 합니다. 이 내용은 다음 문서에서 계속 설명하겠습니다.</dd> + <dt><a href="/ko/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_variables_props">3. Svelte의 동적 동작: 변수와 props 작업</a></dt> + <dd>이제 마크업과 스타일이 준비되었으므로 Svelte To-Do list 앱에 필요한 기능 개발을 시작할 수 있습니다. 이 문서에서는 변수와 props를 사용하여 앱을 동적으로 만듭니다. 할일(todo)을 추가하거나 삭제하고, 완료로 표시하고, 상태별로 필터링 할 수 있습니다.</dd> + <dt><a href="/ko/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_components">4. Svelte app 컴포넌트화</a></dt> + <dd>이 문서의 핵심 목표는 앱을 관리 가능한 컴포넌트로 나누고, 이들간에 정보를 공유하는 방법을 살펴 보는 것입니다. 앱을 컴포넌트화 하고 기능을 추가하여 기존 컴포넌트를 업데이트 할 수 있도록 합니다.</dd> + <dt><a href="/ko/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_reactivity_lifecycle_accessibility">5. 향상된 Svelte: 반응성, 생명주기, 접근성</a></dt> + <dd>이 문서에서는 앱의 최종 기능을 추가하고 앱을 더욱 컴포넌트화 합니다. 객체와 배열의 업데이트와 관련된 반응성(reactivity) 이슈를 처리하는 방법을 배웁니다. 일반적인 함정을 피하기 위해 우리는 Svelte의 반응성 시스템을 좀 더 깊이 공부해야 합니다. 또한 접근성(accessibility ) 관련 이슈를 비롯해 좀 더 많은 내용을 해결하는 방법도 살펴보겠습니다.</dd> + <dt><a href="/ko/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_stores">6. Svelte stores 사용하기</a></dt> + <dd>이 문서에서는 Svelte에서 상태 관리를 처리하는 또 다른 방법을 보여줍니다. <a class="external external-icon" href="https://svelte.dev/tutorial/writable-stores" rel="noopener">스토어(Stores</a>). 스토어는 값을 갖고있는 글로벌 데이터 저장소입니다. 컴포넌트는 스토어를 구독하고 값이 변경되면 알림을 받을 수 있습니다.</dd> + <dt><a href="/ko/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_TypeScript">7. Svelte의 타입스크립트 지원</a></dt> + <dd>이제 Svelte 애플리케이션에서 타입스크립트를 사용하는 방법을 배웁니다. 먼저 타입스크립트가 무엇이며 어떤 이점이 있는지 알아봅니다. 그 다음 타입스크립트 파일과 함께 작동하도록 프로젝트를 구성하는 방법을 살펴봅니다. 마지막으로 앱을 검토하여 타입스크립트 기능을 최대한 활용하기 위해 어떤 수정을 해야 하는지 살펴보겠습니다.</dd> + <dt><a href="/ko/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_deployment_next">8. 배포(Deployment)와 다음단계</a></dt> + <dd>이 마지막 문서에서는 애플리케이션을 배포하고 온라인으로 가져오는 방법을 살펴봅니다. 또한 Svelte 학습 여정을 계속하기 위해 알아야 할 몇 가지 리소스를 공유합니다. </dd> +</dl> + +<h2 id="Which_frameworks_did_we_choose">Which frameworks did we choose?</h2> + +<p>우리는 React/ReactDOM, Ember, Vue의 세 가지 주요 프레임워크에 초점을 맞춘 가이드와 시작하는 글 모음을 함께 게시하고 있습니다. 여기에는 여러가지 이유가 있습니다.</p> + +<ul> + <li>이것들은 잠시동안 인기가 있습니다. 다른 소프트웨어 툴과 마찬가지로 다음주에도 중단되지 않고 적극적으로 개발 되는 도구를 선택하고 유지하는것이 좋습니다. 또한 이것은 구인할 때에도 바람직하게 작용할 겁니다.</li> + <li>이들은 강력한 커뮤니티와 좋은 문서를 갖고 있습니다. 복잡한 주제를 배우는 데 도움을 얻을 수 있다는 것이 특히 중요하고, 처음시작하는 경우라면 더욱 그렇습니다.</li> + <li>우리는 모든 최신 프레임 워크를 다룰 수 있는 리소스가 없습니다. 새로운 목록이 항상 표시되므로 이 목록을 최신 상태로 유지하기가 매우 어려울 수 있습니다.</li> + <li>초심자로서 매우 많은 선택지 중 집중할 것을 선택하는 것은 매우 현실적인 문제입니다. 따라서 목록을 짧게 유지하는것이 좋습니다.</li> +</ul> + +<p>우리는 이것을 미리 말하고 싶습니다. 위 프레임워크들이 최고라고 생각하거나 어떤 식으로든 보증되기 때문에 선택하지 않았습니다. 우리는 단지 이 프레임워크들이 위의 기준에서 높은 점수를 얻었다고 생각합니다.</p> + +<p>이 글을 처음 게시할 때 더 많은 프레임워크가 포함되기를 원했지만, 더 오래 지연시키지 않고 내용을 릴리즈 한 다음에 나중에 프레임워크 가이드를 더 추가하기로 결정했습니다. 이 컨텐츠에 좋아하는 프레임워크가 표시되지 않았고, 이를 변경하고 싶다면 언제든지 저희와 논의하시기 바랍니다. <a href="https://wiki.mozilla.org/Matrix">Matrix</a>나 <a href="https://discourse.mozilla.org/c/mdn">Discourse</a>를 통해 연락하거나 <a href="mailto:mdn-admins@mozilla.org">mdn-admins list</a>로 메일을 보내셔도 됩니다.</p> diff --git a/files/ko/learn/tools_and_testing/client-side_javascript_frameworks/vue_first_component/index.html b/files/ko/learn/tools_and_testing/client-side_javascript_frameworks/vue_first_component/index.html new file mode 100644 index 0000000000..2b2e70e8f6 --- /dev/null +++ b/files/ko/learn/tools_and_testing/client-side_javascript_frameworks/vue_first_component/index.html @@ -0,0 +1,384 @@ +--- +title: 첫 번째 Vue 컴포넌트 만들기 +slug: Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_first_component +translation_of: Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_first_component +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_getting_started","Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_rendering_lists", "Learn/Tools_and_testing/Client-side_JavaScript_frameworks")}}</div> + +<p class="summary">이제 Vue에 대해 더 자세히 알아보고 직접 커스텀 컴포넌트를 만들어 볼 시간입니다. 먼저, Todo 리스트의 각 항목을 표현하는 컴포넌트를 만들어 보면서 몇 가지 중요한 개념을 배우겠습니다. 컴포넌트 내부에서 다른 컴포넌트 호출하기, props를 통해 데이터 넘겨주기, 데이터 상태 저장하기 등을 배울 것입니다. </p> + +<div class="blockIndicator note"> +<p class="summary"><strong>Note</strong>: 필요하다면 <a href="https://github.com/mdn/todo-vue">todo-vue repository</a> 에서 최종 샘플 앱 코드를 확인할 수 있습니다. 완성된 앱의 모습은 <a href="https://mdn.github.io/todo-vue/dist/">https://mdn.github.io/todo-vue/dist/</a>을 참고하세요.</p> +</div> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">사전 요구 사항:</th> + <td> + <p>코어 <a href="/en-US/docs/Learn/HTML">HTML</a>, <a href="/en-US/docs/Learn/CSS">CSS</a>과 <a href="/en-US/docs/Learn/JavaScript">JavaScript</a>에 익숙함, <a href="/en-US/docs/Learn/Tools_and_testing/Understanding_client-side_tools/Command_line">terminal/command line</a>에 대한 지식</p> + + <p>Vue 컴포넌트는 앱의 데이터를 관리하는 JavaScript 객체와 기본 DOM 구조에 매핑되는 HTML 기반 템플릿 구문을 조합해 작성된다. Vue를 설치하고 고급 기능(예: 단일 파일 컴포넌트, render 함수 등)을 사용하려면 node + npm이 설치된 터미널이 필요하다.</p> + </td> + </tr> + <tr> + <th scope="row">목적:</th> + <td>Vue 컴포넌트를 생성하는 법을 배운다. 컴포넌트를 다른 컴포넌트 내부에 render하는 방법, props를 이용해 데이터를 전달하는 방법과 상태를 저장하는 방법을 배운다.</td> + </tr> + </tbody> +</table> + +<h2 id="ToDoItem_컴포넌트_만들기">ToDoItem 컴포넌트 만들기</h2> + +<p>각각의 할 일 항목 (To-Do Item)을 표시해줄 첫 번째 컴포넌트를 작성해봅시다. 이 항목이 모여서 Todo List가 될 것입니다.</p> + +<ol> + <li><code>moz-todo-vue/src/components</code> 디렉토리 안에 <code>ToDoItem.vue</code>라는 이름으로 파일을 생성하고, 에디터에서 파일을 열어주세요.</li> + <li>파일 상단에 <code><template> </template></code> 태그를 추가해 컴포넌트의 템플릿 섹션을 만들어주세요.</li> + <li>템플릿 섹션 밑에 <code><script></script></code> 섹션을 생성하세요. <code><script></code> 태그 안에 default export 오브젝트 <code>export default {}</code>를 추가하세요. 이것이 바로 우리가 만들고 있는 컴포넌트 오브젝트입니다.</li> +</ol> + +<p>여기까지 잘 따라하셨다면 <code>ToDoItem.vue</code> 파일이 아래와 같은 형태가 됩니다.</p> + +<pre class="brush: html notranslate"><template> </template> +<script> + export default {}; +</script></pre> + +<p>이제 <code>ToDoItem</code>에 내용을 추가해보겠습니다. Vue 2의 템플릿은 단일 루트 엘리멘트만을 허용합니다. 즉, 템플릿 섹션 안의 모든 것을 포함하는 하나의 엘리멘트가 존재해야 합니다. (Vue 3에서는 다중 루트 엘리멘트를 지원합니다!) 여기서는 <code><a href="/en-US/docs/Web/HTML/Element/div"><div></a></code> 를 루트 엘리멘트로 지정하겠습니다.</p> + +<ol> + <li> + <p>우선 템플릿 섹션에 빈 <code><div></code> 를 추가하세요.</p> + </li> + <li> + <p><code><div></code> 안에 체크박스와 레이블을 추가해보겠습니다. 아래와 같이 체크박스에 <code>id</code> 를 추가하고, 체크박스 id를 레이블에 매핑하는 <code>for</code> 속성을 추가합니다.</p> + + <pre class="brush: html notranslate"><template> + <div> + <input type="checkbox" id="todo-item" checked="false" /> + <label for="todo-item">My Todo Item</label> + </div> +</template></pre> + </li> +</ol> + +<h3 id="앱_안에서_TodoItem_컴포넌트_사용하기">앱 안에서 TodoItem 컴포넌트 사용하기</h3> + +<p>아주 잘 하고 있어요. 그런데 아직 우리 앱에 컴포넌트를 추가하지 않았기 때문에 잘 작동하는지 테스트할 방법이 없네요. 이제 앱에 컴포넌트를 등록해봅시다. </p> + +<ol> + <li> + <p><code>App.vue</code> 파일을 다시 열어주세요.</p> + </li> + <li> + <p><code><script></code> 태그 상단에 다음을 추가해 <code>ToDoItem</code> 컴포넌트를 임포트하세요:</p> + + <pre class="brush: js notranslate">import ToDoItem from './components/ToDoItem.vue';</pre> + </li> + <li> + <p>컴포넌트 오브젝트 내부에 <code>components</code> 속성을 추가하고, 여기에 <code>ToDoItem</code> 컴포넌트를 등록하세요.</p> + </li> +</ol> + +<p>이제 <code><script></code> 내부가 이런 모양이 되었을 것입니다.</p> + +<pre class="brush: js notranslate">import ToDoItem from './components/ToDoItem.vue'; + +export default { + name: 'app', + components: { + ToDoItem + } +};</pre> + +<p>이전글에서 Vue CLI가 <code>HelloWorld</code> 컴포넌트를 등록했던 것과 같은 방식입니다. </p> + +<p><code>ToDoItem</code> 컴포넌트를 앱에 실제로 렌더링하려면 <code><template></code> 태그 안에서 <code><to-do-item></to-do-item></code> 요소를 사용해야 합니다. JavaScript에서 컴포넌트 파일의 이름과 그 표현은 항상 어퍼카멜케이스(e.g. <code>ToDoList</code>)를 사용하며, 해당 커스텀 엘리멘트는 하이픈으로 연결된 소문자(e.g. <code><to-do-list></code>)로 표현합니다.</p> + +<ol> + <li><code><a href="/en-US/docs/Web/HTML/Element/Heading_Elements"><h1></a></code> 아래에 리스트 아이템(<code><a href="/en-US/docs/Web/HTML/Element/li"><li></a></code>)을 포함하는 비정렬 리스트(<code><a href="/en-US/docs/Web/HTML/Element/ul"><ul></a></code>)를 생성합니다.</li> + <li>리스트 아이템 안에 <code><to-do-item></to-do-item></code>을 추가합니다.</li> +</ol> + +<p><code>App.vue</code> <code><template></code> 은 아래와 같은 모양이 될 것입니다. </p> + +<pre class="brush: html notranslate"><div id="app"> + <h1>To-Do List</h1> + <ul> + <li> + <to-do-item></to-do-item> + </li> + </ul> +</div></pre> + +<p>렌더링된 앱을 다시 확인해보면 체크박스와 레이블로 구성된 <code>ToDoItem</code> 이 보일 것입니다.</p> + +<p><img alt="The current rendering state of the app, which includes a title of To-Do List, and a single checkbox and label" src="https://mdn.mozillademos.org/files/17243/rendered-todoitem.png" style="border-style: solid; border-width: 1px; display: block; height: 142px; margin: 0 auto; width: 385px;"></p> + +<h2 id="props를_사용해_컴포넌트를_동적으로_만들기">props를 사용해 컴포넌트를 동적으로 만들기</h2> + +<p>현재 상태로는 <code>ToDoItem</code> 컴포넌트를 한 페이지에 한 번만 표시할 수 있고(고유 ID가 있어야 함) 레이블 텍스트를 설정할 방법도 없습니다. 동적인 요소가 전혀 없는 상태입니다. </p> + +<p>컴포넌트를 동적으로 만들기 위해서는 컴포넌트의 state(상태)가 필요합니다. 컴포넌트에 props를 추가해 컴포넌트에 상태를 부여할 수 있습니다. props를 함수의 입력이라고 생각하면 이해가 쉬울 것입니다. props 값은 컴포넌트에 초기 상태(initial state)를 부여합니다.</p> + +<h3 id="props_등록하기">props 등록하기</h3> + +<p>Vue에서는 props를 등록하는 방법이 두 가지 있습니다.</p> + +<ul> + <li>첫 번째 방법은 단순히 문자열 어레이로 props를 나열하는 것입니다. 어레이의 각 항목은 각 prop의 이름이 됩니다. </li> + <li>두 번째 방법은 props를 오브젝트로 정의하는 것입니다. 각각의 키가 prop의 이름이 됩니다. 이렇게 props를 오브젝트로 나열하면 기본값을 지정할 수 있고, 해당 prop이 필수값인지 표시할 수 있고, 기본적인 오브젝트 타이핑(특히 JavaScript 원시 타입에 대해)과 간단한 prop 유효성 검증을 할 수 있습니다.</li> +</ul> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: prop의 유효성 검증은 개발 모드에서만 이루어지기 때문에, 상용에서는 이것에 의존해서는 안됩니다. 그리고 이 prop 검증 기능은 컴포넌트 인스턴스가 생성되기 전에 호출되기 때문에 컴포넌트의 상태나 다른 prop에는 접근할 수 없습니다. </p> +</div> + +<p>여기서는 오브젝트 등록 방식을 사용해 props를 등록해보겠습니다.</p> + +<ol> + <li><code>ToDoItem.vue</code> 파일을 열어주세요.</li> + <li>export <code>default {}</code> 오브젝트 안에 <code>props</code> 속성을 추가하고 빈 오브젝트를 만들어주세요.</li> + <li>이 오브젝트 안에 <code>label</code> 과 <code>done</code> 을 키로 사용하는 속성을 추가하세요.</li> + <li><code>label</code> 키의 값은 두 개의 속성을 갖는 오브젝트입니다. + <ol> + <li>첫 번째는 <code>required</code> 속성입니다. 이 속성의 값을 <code>true</code>로 지정하겠습니다. 이 컴포넌트의 모든 인스턴스가 레이블 필드를 반드시 가져야 한다는 의미입니다. 만약 <code>ToDoItem</code> 컴포넌트가 레이블 필드를 갖지 않으면 Vue가 경고해줄 것입니다.</li> + <li>두 번째는 <code>type</code> 속성입니다. 이 속성의 값을 JavaScript <code>String</code>(대문자 S)타입으로 설정합니다. 이렇게 하면 label prop이 스트링 값을 가질 것임을 Vue에게 알려줄 수 있습니다. </li> + </ol> + </li> + <li>이제 <code>done</code> prop으로 넘어가겠습니다. + <ol> + <li>먼저 <code>default</code> 필드를 추가하고, <code>false</code> 값을 지정합니다. 이것은 <code>ToDoItem</code> 컴포넌트가 <code>done</code> prop을 받지 못했을 때, 기본값으로 false를 갖는다는 의미입니다. his means that when no <code>done</code> prop is passed to a <code>ToDoItem</code> component, the <code>done</code> prop will will have a value of false(기본값을 항상 설정할 필요는 없습니다. 필수가 아닌 props에 대해서만 <code>default</code>를 지정하면 됩니다).</li> + <li>다음으로 <code>type</code> 필드를 추가합니다. 값은 <code>Boolean</code>으로 지정합니다. 이 prop이 JavaScript 불리언 타입을 가질 것임을 Vue에게 알려주는 것입니다.</li> + </ol> + </li> +</ol> + +<p>이제 컴포넌트 오브젝트는 아래와 같은 모양이 될 것입니다.</p> + +<pre class="brush: js notranslate"><script> + export default { + props: { + label: { required: true, type: String }, + done: { default: false, type: Boolean } + } + }; +</script></pre> + +<h3 id="등록한_props_사용하기">등록한 props 사용하기</h3> + +<p>With these props defined inside the component object, we can now use these variable values inside our template. Let's start by adding the <code>label</code> prop to the component template.</p> + +<p>In your <code><template></code>, replace the contents of the <code><label></code> element with <code>\{{label}}</code>.</p> + +<p><code>\{{}}</code> is a special template syntax in Vue, which lets us print the result of JavaScript expressions defined in our class, inside our template, including values and methods. It’s important to know that content inside <code>\{{}}</code> is displayed as text and not HTML. In this case, we’re printing the value of the <code>label</code> prop.</p> + +<p>Your component’s template section should now look like this:</p> + +<pre class="brush: html notranslate"><template> + <div> + <input type="checkbox" id="todo-item" checked="false" /> + <label for="todo-item">\{{label}}</label> + </div> +</template></pre> + +<p>Go back to your browser and you'll see the todo item rendered as before, but without a label (oh no!). Go to your browser's DevTools and you’ll see a warning along these lines in the console:</p> + +<pre class="notranslate">[Vue warn]: Missing required prop: "label" + +found in + +---> <ToDoItem> at src/components/ToDoItem.vue + <App> at src/App.vue + <Root> +</pre> + +<p>This is because we marked the <code>label</code> as a required prop, but we never gave the component that prop — we've defined where inside the template we want it used, but we haven't passed it into the component when calling it. Let’s fix that.</p> + +<p>Inside your <code>App.vue </code>file, add a <code>label</code> prop to the <code><to-do-item></to-do-item></code> component, just like a regular HTML attribute:</p> + +<pre class="brush: html notranslate"><to-do-item label="My ToDo Item"></to-do-item></pre> + +<p>Now you'll see the label in your app, and the warning won't be spat out in the console again.</p> + +<p>So that's props in a nutshell. Next we'll move on to how Vue persists data state.</p> + +<h2 id="Vue의_data_object">Vue의 data object</h2> + +<p>If you change the value of the <code>label</code> prop passed into the <code><to-do-item></to-do-item></code> call in your App component, you should see it update. This is great. We have a checkbox, with an updatable label. However, we're currently not doing anything with the "done" prop — we can check the checkboxes in the UI, but nowhere in the app are we recording whether a todo item is actually done.</p> + +<p>To achieve this, we want to bind the component's <code>done</code> prop to the <code>checked</code> attribute on the <code><a href="/en-US/docs/Web/HTML/Element/input"><input></a></code> element, so that it can serve as a record of whether the checkbox is checked or not. However, it's important that props serve as one-way data binding — a component should never alter the value of its own props. There are a lot of reasons for this. In part, components editing props can make debugging a challenge. If a value is passed to multiple children, it could be hard to track where the changes to that value were coming from. In addition, changing props can cause components to re-render. So mutating props in a component would trigger the component to rerender, which may in-turn trigger the mutation again.</p> + +<p>To work around this, we can manage the <code>done</code> state using Vue’s <code>data</code> property. The <code>data</code> property is where you can manage local state in a component, it lives inside the component object alongside the <code>props</code> property and has the following structure:</p> + +<pre class="brush: js notranslate">data() { + return { + key: value + } +}</pre> + +<p>You'll note that the <code>data</code> property is a function. This is to keep the data values unique for each instance of a component at runtime — the function is invoked separately for each component instance. If you declared data as just an object, all instances of that component would share the same values. This is a side-effect of the way Vue registers components and something you do not want.</p> + +<p>You use <code>this</code> to access a component's props and other properties from inside data, as you may expect. We'll see an example of this shortly.</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: Because of the way that <code>this</code> works in arrow functions (binding to the parent’s context), you wouldn’t be able to access any of the necessary attributes from inside <code>data</code> if you used an arrow function. So don’t use an arrow function for the <code>data</code> property.</p> +</div> + +<p>So let's add a <code>data</code> property to our <code>ToDoItem</code> component. This will return an object containing a single property that we'll call <code>isDone</code>, whose value is <code>this.done</code>.</p> + +<p>Update the component object like so:</p> + +<pre class="brush: js notranslate">export default { + props: { + label: { required: true, type: String }, + done: { default: false, type: Boolean } + }, + data() { + return { + isDone: this.done + }; + } +};</pre> + +<p>Vue does a little magic here — it binds all of your props directly to the component instance, so we don’t have to call <code>this.props.done</code>. It also binds other attributes (<code>data</code>, which you’ve already seen, and others like <code>methods</code>, <code>computed</code>, etc.) directly to the instance. This is, in part, to make them available to your template. The down-side to this is that you need to keep the keys unique across these attributes. This is why we called our <code>data</code> attribute <code>isDone</code> instead of <code>done</code>.</p> + +<p>So now we need to attach the <code>isDone</code> property to our component. In a similar fashion to how Vue uses <code>\{{}}</code> expressions to display JavaScript expressions inside templates, Vue has a special syntax to bind JavaScript expressions to HTML elements and components: <code><strong>v-bind</strong></code>. The <code>v-bind</code> expression looks like this:</p> + +<pre class="notranslate">v-bind:attribute="expression"</pre> + +<p>In other words, you prefix whatever attribute/prop you want to bind to with <code>v-bind:</code>. In most cases, you can use a shorthand for the <code>v-bind</code> property, which is to just prefix the attribute/prop with a colon. So <code>:attribute="expression"</code> works the same as <code>v-bind:attribute="expression"</code>.</p> + +<p>So in the case of the checkbox in our <code>ToDoItem</code> component, we can use <code>v-bind</code> to map the <code>isDone</code> property to the <code>checked</code> attribute on the <code><input></code> element. Both of the following are equivalent:</p> + +<pre class="brush: html notranslate"><input type="checkbox" id="todo-item" v-bind:checked="isDone" /> + +<input type="checkbox" id="todo-item" :checked="isDone" /></pre> + +<p>You're free to use whichever pattern you would like. It's best to keep it consistent though. Because the shorthand syntax is more commonly used, this tutorial will stick to that pattern.</p> + +<p>So let's do this. Update your <code><input></code> element now to replace <code>checked="false"</code> with <code>:checked="isDone"</code>.</p> + +<p>Test out your component by passing <code>:done="true"</code> to the <code>ToDoItem</code> call in <code>App.vue</code>. Note that you need to use the <code>v-bind</code> syntax, because otherwise <code>true</code> is passed as a string. The displayed checkbox should be checked.</p> + +<pre class="brush: js notranslate"><template> + <div id="app"> + <h1>My To-Do List</h1> + <ul> + <li> + <to-do-item label="My ToDo Item" :done="true"></to-do-item> + </li> + </ul> + </div> +</template> +</pre> + +<p>Try changing <code>true</code> to <code>false</code> and back again, reloading your app in between to see how the state changes.</p> + +<h2 id="Todos에_고유_id_부여하기">Todos에 고유 id 부여하기</h2> + +<p>Great! We now have a working checkbox where we can set the state programmatically. However, we can currently only add one <code>ToDoList</code> component to the page because the <code>id</code> is hardcoded. This would result in errors with assistive technology since the <code>id</code> is needed to correctly map labels to their checkboxes. To fix this, we can programmatically set the <code>id</code> in the component data.</p> + +<p>We can use the <a href="https://www.npmjs.com/package/lodash">lodash</a> package's <code>uniqueid()</code> method to help keep the index unique. This package exports a function that takes in a string and appends a unique integer to the end of the prefix. This will be sufficient for keeping component <code>id</code>s unique.</p> + +<p>Let’s add the package to our project with npm; stop your server and enter the following command into your terminal:</p> + +<pre class="brush: bash notranslate">npm install --save lodash.uniqueid</pre> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: If you prefer yarn, you could instead use <code>yarn add lodash.uniqueid</code>.</p> +</div> + +<p>We can now import this package into our <code>ToDoItem</code> component. Add the following line at the top of <code>ToDoItem.vue</code>’s <code><script></code> element:</p> + +<pre class="brush: js notranslate">import uniqueId from 'lodash.uniqueid';</pre> + +<p>Next, add add an <code>id</code> field to our data property, so the component object ends up looking like so (<code>uniqueId()</code> returns the specified prefix — <code>todo-</code> — with a unique string appended to it):</p> + +<pre class="brush: js notranslate">import uniqueId from 'lodash.uniqueid'; + +export default { + props: { + label: { required: true, type: String }, + done: { default: false, type: Boolean } + }, + data() { + return { + isDone: this.done, + id: uniqueId('todo-') + }; + } +};</pre> + +<p>Next, bind the <code>id</code> to both our checkbox’s <code>id</code> attribute and the label’s <code>for</code> attribute, updating the existing <code>id</code> and <code>for</code> attributes as shown:</p> + +<pre class="brush: js notranslate"><template> + <div> + <input type="checkbox" :id="id" :checked="isDone" /> + <label :for="id">\{{label}}</label> + </div> +</template></pre> + +<h2 id="정리">정리</h2> + +<p>And that will do for this article. At this point we have a nicely-working <code>ToDoItem</code> component that can be passed a label to display, will store its checked state, and will be rendered with a unique <code>id</code> each time it is called. You can check if the unique <code>id</code>s are working by temporarily adding more <code><to-do-item></to-do-item></code> calls into <code>App.vue</code>, and then checking their rendered output with your browser's DevTools.</p> + +<p><span class="author-d-1gg9uz65z1iz85zgdz68zmqkz84zo2qoxwoxz78zz83zz84zz69z2z80zgwxsgnz83zfkt5e5tz70zz68zmsnjz122zz71z">Now we're ready to add multiple <code>ToDoItem</code> components to our App. In our next article we'll look at adding a set of todo item data to our <code>App.vue</code> component, which we'll then loop through and display inside <code>ToDoItem</code> components using the <code>v-for</code> directive. </span></p> + +<p>{{PreviousMenuNext("Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_getting_started","Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_rendering_lists", "Learn/Tools_and_testing/Client-side_JavaScript_frameworks")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Introduction">Introduction to client-side frameworks</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Main_features">Framework main features</a></li> + <li>React + <ul> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_getting_started">Getting started with React</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_todo_list_beginning">Beginning our React todo list</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_components">Componentizing our React app</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_interactivity_events_state">React interactivity: Events and state</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_interactivity_filtering_conditional_rendering">React interactivity: Editing, filtering, conditional rendering</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_accessibility">Accessibility in React</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_resources">React resources</a></li> + </ul> + </li> + <li>Ember + <ul> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_getting_started">Getting started with Ember</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_structure_componentization">Ember app structure and componentization</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_interactivity_events_state">Ember interactivity: Events, classes and state</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_conditional_footer">Ember Interactivity: Footer functionality, conditional rendering</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_routing">Routing in Ember</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_resources">Ember resources and troubleshooting</a></li> + </ul> + </li> + <li>Vue + <ul> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_getting_started">Getting started with Vue</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_first_component">Creating our first Vue component</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_rendering_lists">Rendering a list of Vue components</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_methods_events_models">Adding a new todo form: Vue events, methods, and models</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_styling">Styling Vue components with CSS</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_computed_properties">Using Vue computed properties</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_conditional_rendering">Vue conditional rendering: editing existing todos</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_refs_focus_management">Focus management with Vue refs</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_resources">Vue resources</a></li> + </ul> + </li> + <li>Svelte + <ul> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_getting_started">Getting started with Svelte</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_Todo_list_beginning">Starting our Svelte Todo list app</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_variables_props">Dynamic behavior in Svelte: working with variables and props</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_components">Componentizing our Svelte app</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_reactivity_lifecycle_accessibility">Advanced Svelte: Reactivity, lifecycle, accessibility</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_stores">Working with Svelte stores</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_TypeScript">TypeScript support in Svelte</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_deployment_next">Deployment and next steps</a></li> + </ul> + </li> +</ul> diff --git a/files/ko/learn/tools_and_testing/client-side_javascript_frameworks/vue_getting_started/index.html b/files/ko/learn/tools_and_testing/client-side_javascript_frameworks/vue_getting_started/index.html new file mode 100644 index 0000000000..0ea628b883 --- /dev/null +++ b/files/ko/learn/tools_and_testing/client-side_javascript_frameworks/vue_getting_started/index.html @@ -0,0 +1,293 @@ +--- +title: Vue 시작하기 +slug: Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_getting_started +translation_of: Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_getting_started +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_resources","Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_first_component", "Learn/Tools_and_testing/Client-side_JavaScript_frameworks")}}</div> + +<p class="summary">이제 우리가 배울 세 번째 프레임워크인 Vue를 소개하겠습니다. 이 글에서 우리는 Vue에 대한 간단한 배경지식을 얻고, Vue를 설치하고 새로운 프로젝트를 만드는 방법을 배웁니다. 또한 전체 프로젝트와 컴포넌트의 주요 구조를 공부하고, 로컬에서 프로젝트를 실행하는 방법을 살펴본 후 예제 프로젝트를 구성해봅니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">사전 요구 사항:</th> + <td> + <p>코어 <a href="https://wiki.developer.mozilla.org/en-US/docs/Learn/HTML">HTML</a>, <a href="https://wiki.developer.mozilla.org/en-US/docs/Learn/CSS">CSS</a> 및 <a href="https://wiki.developer.mozilla.org/en-US/docs/Learn/JavaScript">JavaScript</a> 언어에 익숙함. 터미널/커맨드라인에 대한 지식.<br> + <br> + Vue 컴포넌트는 앱의 데이터를 관리하는 JavaScript 객체와 기본 DOM 구조에 매핑되는 HTML 기반 템플릿 구문을 조합해 작성된다. Vue를 설치하고 고급 기능(예: 단일 파일 컴포넌트, render 함수 등)을 사용하려면 node + npm이 설치된 터미널이 필요하다.</p> + </td> + </tr> + <tr> + <th scope="row">목적:</th> + <td>Vue 로컬 개발 환경을 구성한다. 스타터 앱을 만들고 기본적인 동작 원리를 이해한다.</td> + </tr> + </tbody> +</table> + +<h2 id="더_선명한_Vue">더 선명한 Vue</h2> + +<p>Vue는 최신의 JavaScript 프레임워크로 <a href="/ko/docs/Glossary/Progressive_Enhancement">점진적 향상</a>을 위한 유용한 기능을 제공합니다. 다른 많은 프레임워크와는 달리, Vue를 사용하면 기존의 HTML 코드를 향상시킬 수 있습니다. 이를 통해 아주 쉽게 <a href="/en-US/docs/Glossary/jQuery">JQuery</a> 등의 라이브러리를 Vue로 대체할 수 있습니다. </p> + +<p>물론 Vue를 이용해 완전한 단일 페이지 애플리케이션(SPA)을 작성할 수도 있습니다. 이렇게 하면 전체적으로 Vue가 관리하는 마크업을 만들 수 있고, 복잡한 애플리케이션에 대한 개발자 경험과 성능을 향상시킬 수 있습니다. 필요하다면 클라이언트 사이드 라우팅 및 상태 관리 라이브러리를 활용할 수 있다는 장점도 있습니다. Vue는 이와 같은 클라이언트 사이드 라우팅이나 상태 관리에 대해 "미들 그라운드" 접근 방식을 취합니다. Vue 코어 팀은 이런 기능을 위한 (vue-router, vuex 등의) 라이브러리를 유지보수하고 있지만, Vue에 직접 번들로 제공하지는 않습니다. 그러므로 우리가 만들 애플리케이션에 더 적합한 라우팅/상태 관리 라이브러리가 있다면 그것을 선택할 수 있습니다. </p> + +<p>Vue는 애플리케이션에 Vue를 점진적으로 통합시킬 수 있도록 하며, 마크업 작성에 대해서도 점진적 접근법을 제공합니다. 다른 많은 프레임워크처럼, Vue에서도 컴포넌트를 통해 재사용 가능한 마크업 블록을 생성할 수 있습니다. 대부분의 경우 Vue 컴포넌트는 특별한 HTML 템플릿 구문으로 작성됩니다. HTML에서 가능한 것 이상의 제어가 필요하다면, JSX나 일반 JavaScript 함수를 이용해 컴포넌트를 정의할 수 있습니다. </p> + +<p>이 튜토리얼을 진행하는 동안, 다른 탭에 <a href="https://vuejs.org/v2/guide/">Vue 가이드 </a>와 <a href="https://vuejs.org/v2/api/">API 문서</a>를 열어 두고 각 항목에 대해 더 자세한 정보가 필요할 때 참조하세요. Vue와 다른 프레임워크 간의 비교(편향될 가능성 있음)는 <a href="https://vuejs.org/v2/guide/comparison.html">Vue 문서: 다른 프레임워크와의 비교</a>를 참조하세요.</p> + +<h2 id="설치하기">설치하기</h2> + +<p>기존 사이트에서 Vue를 사용하려면 아래 <code><a href="/en-US/docs/Web/HTML/Element/script"><script></a></code> 요소 중 하나를 페이지에 추가하면 됩니다. 이 한 줄을 추가하는 것만으로 기존의 사이트에서 Vue를 사용할 수 있습니다. Vue가 자칭 '프로그레시브 프레임워크'임을 강조하는 이유가 바로 이것입니다. JQuery 등의 라이브러리를 사용하는 기존 프로젝트를 Vue로 마이그레이션하려고 할 때 아주 좋은 옵션입니다. 이 방식으로 속성, 커스텀 컴포넌트, 데이터 관리 등 수많은 Vue의 핵심 기능을 사용할 수 있게 됩니다. </p> + +<ul> + <li> + <p>개발 스크립트 (최적화되지 않음. 콘솔 경고 포함. 개발용으로 좋음.)</p> + + <pre class="brush: html notranslate"><script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script></pre> + </li> + <li> + <p>상용 스크립트 (최적화 버전. 콘솔 경고 최소화. 업데이트로 인해 사이트가 영향을 받지 않도록 버전 번호를 명시하는 것이 좋다.)</p> + + <pre class="brush: html notranslate"><script src="https://cdn.jsdelivr.net/npm/vue@2"></script></pre> + </li> +</ul> + +<p>하지만 이 방식은 한계가 있습니다. 좀 더 복잡한 앱을 구성하려면 <a href="https://www.npmjs.com/package/vue">Vue NPM package</a>를 사용하는 것이 좋습니다. Vue NPM 패키지를 사용하면 Vue의 고급 기능을 이용할 수 있고, WebPack 같은 번들 도구를 활용할 수 있습니다. 그리고 Vue CLI를 사용하면 개발 과정을 간소화해 Vue 앱을 더욱 쉽게 구성할 수 있습니다. npm 패키지와 CLI를 사용하기 위해 필요한 사항은 다음과 같습니다.</p> + +<ol> + <li>Node.js 8.11 이상 설치</li> + <li>npm 또는 yarn</li> +</ol> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: 아직 위 항목을 설치하지 않았다면, <a href="/en-US/docs/Learn/Tools_and_testing/Understanding_client-side_tools/Command_line#Adding_powerups">more about installing npm and Node.js</a> 를 참고하세요.</p> +</div> + +<p>CLI를 설치하기 위해 아래 커맨드를 터미널에서 실행하세요.<br> + npm을 사용하는 경우:</p> + +<pre class="brush: bash notranslate">npm install --global @vue/cli</pre> + +<p>yarn을 사용하는 경우:</p> + +<pre class="brush: bash notranslate">yarn global add @vue/cli</pre> + +<p>설치가 모두 완료되면, 프로젝트를 생성할 디렉토리에서 터미널을 열고 <code>vue create <프로젝트 이름></code> 를 실행해봅시다. 그러면 Vue CLI는 우리가 사용할 수 있는 프로젝트 구성 목록을 보여줄 것입니다. 미리 설정되어 있는 몇 가지 구성 중 골라서 사용해도 되고, 모든 것을 직접 구성할 수도 있습니다. 이 옵션을 통해 우리는 TypeScript, linting, vue-router, 테스트 등의 항목을 구성할 수 있습니다.</p> + +<p>더 자세한 내용은 아래에서 살펴보겠습니다.</p> + +<h2 id="새로운_프로젝트_시작하기">새로운 프로젝트 시작하기</h2> + +<p>Vue의 다양한 기능을 알아보기 위해, 예제로 할 일 목록(todo list) 앱을 만들어보려고 합니다. Vue CLI를 사용해서 새로운 앱을 구성해봅시다. 아래 내용을 순서대로 따라해보세요:</p> + +<ol> + <li>터미널에서 <code>cd <디렉토리></code>를 입력해 샘플 앱을 만들 위치로 이동하고, <code>vue create moz-todo-vue</code>를 실행하세요.</li> + <li>방향키와 <kbd>Enter</kbd>를 사용해 "Manually select features" 옵션을 선택하세요.</li> + <li>첫 번째 메뉴에서 프로젝트에 포함하고 싶은 기능들을 선택할 수 있습니다. "Babel"과 "Linter / Formatter"가 선택되어 있나요? 선택되어 있지 않다면 방향키와 스페이스바를 사용해 선택해주세요. 그리고 <kbd>Enter</kbd>를 누릅니다.</li> + <li>다음으로 linter / formatter 구성을 선택하겠습니다. "Eslint with error prevention only"로 이동하고 다시 <kbd>Enter</kbd>를 눌러주세요. 흔히 생기는 에러를 잡는데 도움을 주면서도 너무 엄격하지는 않은 옵션을 선택했습니다.</li> + <li>다음은 자동 lint를 어떤 방식으로 하고 싶은지 묻는 메세지가 표시될 것입니다. "Lint on save"를 선택하세요. 우리가 프로젝트 내부의 파일을 저장할 때 에러를 체크하라는 의미입니다. 이제 <kbd>Enter</kbd> 를 누르세요.</li> + <li>이제 구성 파일을 어떻게 관리할지 선택해야 합니다. "In dedicated config files" 옵션을 선택하면 ESLint와 같은 것들의 구성 설정을 그들의 전용 파일에 넣게 됩니다. "In package.json" 옵션의 경우, 모든 구성 설정을 앱의 <code>package.json</code> 파일에 넣습니다. 우선 지금은 "In dedicated config files" 옵션을 선택하고 <kbd>Enter</kbd>를 누릅시다.</li> + <li>마지막으로, 지금까지 설정한 내용을 다음에 다시 사용하고 싶은지(현재 설정을 사전 설정 목록에 추가하고 싶은지) 묻는 메세지가 표시됩니다. 이 부분은 여러분이 하고 싶은대로 하시면 돼요. 만약 이 설정을 다음에도 다시 사용하고 싶다면 <kbd>y</kbd>를, 아니라면 <kbd>n</kbd>을 누르세요.</li> +</ol> + +<p>이제 CLI가 우리의 프로젝트를 위한 발판을 만들기 시작하고 우리의 앱을 위한 모든 디펜던시를 설치할 것입니다. </p> + +<p>만약 이전에 한 번도 Vue CLI를 사용해본 적 없다면, 위에서 설명하지 않은 질문이 한 가지 더 표시될 것입니다. 패키지 매니저를 고르라는 메세지가 나타나면, 여러분이 선호하는 것을 고르면 됩니다. 지금부터는 여러분이 선택한 패키지 매니저(npm / yarn)가 기본값으로 설정됩니다. 만약 이 기본값을 변경하고 싶다면 <code>vue create</code> 커맨드를 실행할 때 <code>--packageManager=<package-manager></code> 플래그를 추가하면 됩니다. 다시 말해, 만약 여러분이 이전에 yarn을 사용했지만 다음에는 npm을 사용하도록 프로젝트를 생성하고 싶다면 <code>vue create moz-todo-vue --packageManager=npm</code>을 실행하면 됩니다.</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: 모든 옵션을 여기서 설명하지는 않았습니다. 자세한 내용은 <a href="https://cli.vuejs.org">find more information on the CLI</a> 를 참고하세요.</p> +</div> + +<h2 id="프로젝트_구조">프로젝트 구조</h2> + +<p>위의 모든 내용이 성공적으로 진행됐다면, Vue CLI가 우리의 프로젝트에 사용할 디렉토리와 파일을 생성했을 것입니다. 다음은 그 중 가장 중요한 파일과 디렉토리에 대한 설명입니다.</p> + +<ul> + <li><code>.eslintrc.js</code>: <a href="https://eslint.org/">eslint</a>의 config 파일입니다. linting 규칙을 이 파일에서 관리할 수 있습니다.</li> + <li><code>babel.config.js</code>: <a href="https://babeljs.io/">Babel</a>의 config 파일입니다. Babel은 개발용으로 사용하는 최신 JavaScript 기능을 상용 브라우저 호환이 가능하도록 구버전으로 번역하는 역할을 합니다. 대표적으로, ECMA Script 2015(비공식적으로 ES6라고도 불림)로 작성된 코드를 ES5로 변환해 IE 등의 브라우저에서 동작할 수 있도록 해주는 것이 Babel이 하는 일입니다. 이 파일에 부가적인 babel 플러그인을 등록할 수 있습니다.</li> + <li><code>.browserslistrc</code>: <a href="https://github.com/browserslist/browserslist">Browserslist</a>의 config 파일입니다. 우리가 사용하는 도구를 어떤 브라우저에 최적화할지 이 파일에 정의할 수 있습니다.</li> + <li><code>public</code>: public 디렉토리는 <a href="https://webpack.js.org/">Webpack</a>의 처리를 받지 않고 퍼블리싱되는 정적 자산(static assets)을 포함합니다. (단, <code>index.html</code>의 경우 일부 Webpack의 처리를 받습니다) + <ul> + <li><code>favicon.ico</code>: 앱의 대표 favicon 파일입니다. 기본값으로 Vue 로고가 들어가 있습니다.</li> + <li><code>index.html</code>: 앱의 템플릿 파일입니다. 우리의 Vue 앱은 이 HTML 페이지로부터 실행됩니다. lodash 템플릿 구문을 사용해 보간법으로 값을 지정할 수 있습니다. + <div class="note"><strong>Note</strong>: index.html 파일은 애플리케이션 레이아웃을 관리하는 템플릿이 아닙니다. 이 파일은 Vue 앱 외부의 정적 HTML을 제어하는 템플릿입니다. 고급 사용 사례를 제외하면 이 파일을 직접 편집할 일은 거의 없습니다.</div> + </li> + </ul> + </li> + <li><code>src</code>: 우리의 Vue 애플리케이션의 핵심 내용을 포함하게 될 디렉토리입니다. + <ul> + <li><code>main.js</code>: 이 파일은 애플리케이션의 진입점입니다. 현재 이 파일은 Vue 앱을 초기화하고 <code>index.html</code> 파일에서 어떤 HTML 엘리멘트를 앱에 붙여야 하는지 (예제 프로젝트에서는 #app 엘리멘트) 나타냅니다. 이 파일에 전역 컴포넌트나 부가적인 Vue 라이브러리를 등록하는 경우가 많습니다. </li> + <li><code>App.vue</code>: Vue 애플리케이션의 최상위 컴포넌트입니다. Vue 컴포넌트에 대한 자세한 내용은 아래를 참조하세요.</li> + <li><code>components</code>: 우리가 앞으로 만들 Vue 컴포넌트를 저장할 디렉토리입니다. 지금은 한 개의 예시 컴포넌트만을 포함하고 있습니다.</li> + <li><code>assets</code>: CSS나 이미지 등의 정적 자산(static assets)을 저장하는 디렉토리입니다. 이 파일들은 src 디렉토리에 포함되어 있기 때문에 Webpack의 처리를 받습니다. 즉, <a href="https://sass-lang.com/">Sass/SCSS</a>나 <a href="https://stylus-lang.com/">Stylus</a>와 같은 전처리 도구를 사용할 수 있다는 의미입니다.</li> + </ul> + </li> +</ul> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: 새로운 프로젝트를 생성할 때 어떤 옵션을 선택했는지에 따라, 위에 소개되지 않은 디렉토리가 생길 수도 있습니다. 예를 들어 router 옵션을 선택했다면 <code>views</code>가 생성됩니다.</p> +</div> + +<h2 id=".vue_파일_단일_파일_컴포넌트">.vue 파일 (단일 파일 컴포넌트)</h2> + +<p>다른 많은 프론트엔드 프레임워크와 마찬가지로, Vue 앱을 구축할 때도 컴포넌트가 중심적인 역할을 합니다. 대규모 애플리케이션을 여러 개의 개별 컴포넌트로 분리해 별도로 생성/구축하고, 필요한 경우 각 컴포넌트간에 데이터를 주고 받을 수 있습니다. 이 작은 블록들은 우리가 코드에 대해 추론하고 테스트하기 쉽도록 도와줍니다.</p> + +<p>일부 프레임워크에서는 템플릿과 로직, 스타일링 코드를 각각 분리된 파일에 작성하기를 권장하지만, Vue는 이와 정반대의 방식을 채택합니다. 단일 파일 컴포넌트(<a href="https://vuejs.org/v2/guide/single-file-components.html">Single File Components</a>)를 사용하면, Vue는 템플릿과 이에 대응하는 스크립트, CSS를 모두 하나의 <code>.vue</code> 파일에 묶어서 작성하도록 합니다. 이 파일들은 Webpack과 같은 JS 빌드 도구를 통해 처리됩니다. 그러므로 프로젝트에서 빌드 타임 도구들을 사용할 수 있다는 장점이 있습니다. 즉 우리는 Bable, TypeScript, SCSS 같은 도구를 사용해 더욱 정교한 컴포넌트를 생성할 수 있습니다.</p> + +<p>게다가 Vue CLI로 생성한 프로젝트는 즉시 Webpack과 함께 <code>.vue</code> 파일을 사용할 수 있도록 구성됩니다. 우리가 Vue CLI로 생성한 예제 프로젝트의 src 폴더를 열어 보면 <code>App.vue</code>가 생성된 것을 확인할 수 있습니다.</p> + +<p>이제 App.vue를 좀 더 알아봅시다.</p> + +<h3 id="App.vue">App.vue</h3> + +<p><code>App.vue</code> 파일을 열어보세요. 이 파일이 세 부분으로 이루어져 있다는 것을 바로 확인할 수 있습니다. 바로 컴포넌트 템플릿을 정의하는 <code><template></code> 파트, 스크립트를 작성하는 <code><script></code> 파트, 그리고 스타일링 정보를 작성하는 <code><style></code> 파트입니다. 모든 단일 파일 컴포넌트는 이러한 기본 구조로 이루어져 있습니다.</p> + +<p><code><template></code> 은 컴포넌트의 모든 마크업 구조와 디스플레이 로직을 포함합니다. 이 템플릿은 HTML 구문은 물론이고, 일부 Vue에 특화된 구문도 포함할 수 있습니다. Vue 관련 구문은 나중에 더 자세히 알아보겠습니다.</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: <code><template></code> 태그에 <code>lang</code> 속성을 지정해 표준 HTML 대신 Pug 템플릿을 사용할 수 있습니다: <code><template lang="pug"></code>. 이 튜토리얼에서는 표준 HTML을 계속 사용할 예정이지만, 이렇게 Pug 등의 다른 템플릿을 사용할 수도 있다는 걸 소개해보았습니다.</p> +</div> + +<p><code><script></code>는 컴포넌트 화면에 표시되지 않는 모든 로직을 포함하고 있습니다. 가장 중요한 것은 <code><script></code> 태그 안에 반드시 기본으로 export되는 (하단 코드의 export default 구문 참고) JS 오브젝트가 있어야 한다는 것입니다. 이 오브젝트에서 로컬 컴포넌트 등록, 컴포넌트 인풋(props) 정의, 로컬 상태 관리, 메서드 정의 등 작업이 이루어집니다. 빌드 단계에서 이 오브젝트가 처리되고, 템플릿과 함께 <code>render()</code> 함수를 통해 Vue 컴포넌트로 변환됩니다. </p> + +<p><code>App.vue</code>를 살펴보면, 현재 default export 오브젝트는 컴포넌트 이름을 <code>app</code>으로 설정하고 <code>components</code> 속성에 <code>HelloWorld</code> 컴포넌트를 등록합니다. 이런 식으로 컴포넌트를 등록하면 로컬 컴포넌트가 됩니다. 이렇게 로컬로 등록된 컴포넌트는 이 컴포넌트를 등록한 상위 컴포넌트 내부에서만 사용할 수 있으므로, 각각의 컴포넌트 파일에서 필요한 컴포넌트를 임포트하고 등록해야 합니다. 앱의 모든 페이지가 모든 컴포넌트를 사용하는 것은 아니기 때문에, 번들 분할/트리 쉐이킹에 유용한 기능입니다. </p> + +<pre class="brush: js notranslate">import HelloWorld from './components/HelloWorld.vue'; + +export default { + name: 'app', + components: { + //You can register components locally here. + HelloWorld + } +};</pre> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: <a href="https://www.typescriptlang.org/">TypeScript</a> 문법을 사용하고 싶다면, <code><script></code> 태그 안에 <code>lang</code> 속성을 설정해 컴파일러에게 TypeScript를 사용하고 있다고 알려주세요: <code><script lang="ts"></code></p> +</div> + +<p><code><style></code> 에는 컴포넌트에서 사용할 CSS를 포함합니다. <code><style scoped></code>와 같이 <code>scoped</code> 속성을 추가하면 Vue는 그 안의 내용을 SFC(단일 파일 컴포넌트) 내부 범위에서만 적용합니다. CSS-in-JS 방식과 비슷하게 동작하지만, 여기서는 일반 CSS 구문을 작성할 수 있다는 차이점이 있습니다. </p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: CLI로 프로젝트를 생성할 때 CSS 전처리기를 선택했다면, 빌드타임에 Webpack에서 내용을 처리할 수 있도록 <code><style></code> 태그에 <code>lang</code> 속성을 추가할 수 있습니다. 예를 들어 <code><style lang="scss"></code> 라고 작성하면 스타일링 정보에 SCSS 문법을 사용할 수 있습니다. </p> +</div> + +<h2 id="로컬에서_앱_실행하기">로컬에서 앱 실행하기</h2> + +<p>Vue CLI는 개발 서버를 내장하고 있습니다. 앱을 로컬로 실행할 수 있기 때문에, 직접 서버를 구성할 필요 없이 쉽게 테스트해볼 수 있습니다. 프로젝트의 <code>package.json</code> 파일을 열어보면, CLI가 npm 스크립트로 <code>serve</code> 명령어를 추가해놓은 것을 확인할 수 있습니다. </p> + +<p>터미널을 열고, <code>npm run serve</code> (yarn을 사용한다면 <code>yarn serve</code>)를 실행해보세요. 아래 내용이 나타날 것입니다.</p> + +<pre class="notranslate">INFO Starting development server... +98% after emitting CopyPlugin + + DONE Compiled successfully in 18121ms + + App running at: + - Local: <http://localhost:8080/> + - Network: <http://192.168.1.9:8080/> + + Note that the development build is not optimized. + To create a production build, run npm run build.</pre> + +<p>브라우저 탭을 열고 위의 “local” 주소로 (위 내용처럼 <code>http://localhost:8080</code>이거나 설정에 따라 다를 수 있음) 이동해보면, 아래 사진과 같은 앱이 나타날 것입니다. 환영 메시지, Vue 문서 링크, 우리가 선택한 CLI 플러그인 링크, 기타 유용한 Vue 커뮤니티와 생태계 링크 등이 표시되고 있습니다.</p> + +<p><img alt="default vue app render, with vue logo, welcome message, and some documentation links" src="https://mdn.mozillademos.org/files/17240/vue-default-app.png" style="border-style: solid; border-width: 1px; height: 779px; width: 1600px;"></p> + +<h2 id="약간의_변경_사항_적용하기">약간의 변경 사항 적용하기</h2> + +<p>일단 Vue 로고를 제거합시다. <code>App.vue</code> 파일을 열고, 템플릿 섹션에서 <code><a href="/en-US/docs/Web/HTML/Element/img"><img></a></code> 요소를 지워보세요.</p> + +<pre class="brush: html notranslate"><span class="author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90z8h7gz67ziz76zcz77zz80zz71zncfz69zz69ziaz82zz71zz72zhz77zz122zz90z14mcyd"><img alt="Vue logo" src="./assets/logo.png"></span></pre> + +<p>서버가 아직 실행중이라면, 거의 즉시 로고가 제거되는 것을 확인할 수 있을 것입니다. 템플릿 섹션에서 <code>HelloWorld</code> 컴포넌트도 삭제해봅시다.</p> + +<p>가장 먼저 아래 라인을 지워주세요.</p> + +<pre class="brush: html notranslate"><HelloWorld msg="Welcome to Your Vue.js App"/></pre> + +<p>이제 <code>App.vue</code> 파일을 저장해보면 <code>HelloWorld</code> 컴포넌트를 등록했으나 사용하지 않았다는 에러가 발생할 것입니다. 해당 컴포넌트를 임포트하고 등록하는 코드 역시 지워야 합니다.</p> + +<p>이제 아래 라인도 삭제해보세요.</p> + +<pre class="brush: js notranslate">import HelloWorld from './components/HelloWorld.vue'</pre> + +<pre class="brush: js notranslate">components: { + HelloWorld +}</pre> + +<p>이제 더는 에러가 발생하지 않는 것을 확인할 수 있습니다. 다만 <code><template></code> 파트에 표시할 내용이 없기 때문에 빈 페이지만 보일 것입니다. </p> + +<p>그럼 이제 <code><div id="app"></code> 안에 <code><h1></code> 요소를 추가해보세요. 우리는 todo list 앱을 만들 거니까, 헤더 텍스트를 "To-Do List"라고 작성해봅시다.</p> + +<pre class="brush: html notranslate"><template> + <div id="app"> + <h1>To-Do List</h1> + </div> +</template></pre> + +<p><code>App.vue</code> 는 우리가 원했던 대로 'To-Do List'라는 내용의 헤더를 표시할 것입니다!</p> + +<h2 id="정리">정리</h2> + +<p>우리는 이 장에서 Vue에 숨겨진 몇 가지 아이디어를 배우고, 우리의 예제 애플리케이션의 기초 구조를 만들고, 이를 살펴보고, 몇 가지 변경 사항을 적용해보았습니다. </p> + +<p>이제 기본적인 소개는 끝났으니, 좀 더 나아가서 우리의 샘플 애플리케이션인 To-Do List 앱을 구현해봐야겠죠? 할 일 목록을 저장하고 일을 완료하면 체크하는 기능, 모든 아이템/완료된 아이템/아직 완료되지 않은 아이템을 필터링할 수 있는 기능을 구현해야 합니다.</p> + +<p>다음 글에서는 우리의 첫 커스텀 컴포넌트를 작성하고, props 전달 및 데이터 상태 저장과 같은 몇 가지 중요한 개념을 살펴보겠습니다.</p> + +<p>{{PreviousMenuNext("Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_resources","Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_first_component", "Learn/Tools_and_testing/Client-side_JavaScript_frameworks")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Introduction">Introduction to client-side frameworks</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Main_features">Framework main features</a></li> + <li>React + <ul> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_getting_started">Getting started with React</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_todo_list_beginning">Beginning our React todo list</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_components">Componentizing our React app</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_interactivity_events_state">React interactivity: Events and state</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_interactivity_filtering_conditional_rendering">React interactivity: Editing, filtering, conditional rendering</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_accessibility">Accessibility in React</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/React_resources">React resources</a></li> + </ul> + </li> + <li>Ember + <ul> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_getting_started">Getting started with Ember</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_structure_componentization">Ember app structure and componentization</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_interactivity_events_state">Ember interactivity: Events, classes and state</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_conditional_footer">Ember Interactivity: Footer functionality, conditional rendering</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_routing">Routing in Ember</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Ember_resources">Ember resources and troubleshooting</a></li> + </ul> + </li> + <li>Vue + <ul> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_getting_started">Getting started with Vue</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_first_component">Creating our first Vue component</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_rendering_lists">Rendering a list of Vue components</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_methods_events_models">Adding a new todo form: Vue events, methods, and models</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_styling">Styling Vue components with CSS</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_computed_properties">Using Vue computed properties</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_conditional_rendering">Vue conditional rendering: editing existing todos</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_refs_focus_management">Focus management with Vue refs</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_resources">Vue resources</a></li> + </ul> + </li> + <li>Svelte + <ul> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_getting_started">Getting started with Svelte</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_Todo_list_beginning">Starting our Svelte Todo list app</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_variables_props">Dynamic behavior in Svelte: working with variables and props</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_components">Componentizing our Svelte app</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_reactivity_lifecycle_accessibility">Advanced Svelte: Reactivity, lifecycle, accessibility</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_stores">Working with Svelte stores</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_TypeScript">TypeScript support in Svelte</a></li> + <li><a href="/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_deployment_next">Deployment and next steps</a></li> + </ul> + </li> +</ul> diff --git a/files/ko/learn/tools_and_testing/github/index.html b/files/ko/learn/tools_and_testing/github/index.html new file mode 100644 index 0000000000..cbae0f0cc3 --- /dev/null +++ b/files/ko/learn/tools_and_testing/github/index.html @@ -0,0 +1,82 @@ +--- +title: Git and GitHub +slug: Learn/Tools_and_testing/GitHub +tags: + - GitHub + - git + - 깃허브 +translation_of: Learn/Tools_and_testing/GitHub +--- +<div>{{LearnSidebar}}{{draft}}</div> + +<p class="summary">모든 개발자는 <strong>버전 관리 시스템 </strong>(<strong>VCS</strong>)을 사용하거나 앞으로 그럴 것이다. VCS는 다른 개발자와의 협업 시 코드 중복작성으로 인한 손실을 방지해 주고, 문재가 생겼을 시 이전 버전으로의 롤백을 쉽게 해준다. 가장 유명한 VCS는 Git와 그와 관련된 소셜 코딩 사이트, GitHub이다. 이 글은 이 두가지에 대해 설명할 것이다.</p> + +<h2 id="개요">개요</h2> + +<p>VCS는 소프트웨어 개발을 할 때 필수적이다.</p> + +<ul> + <li>프로젝트를 완전히 직접 수행하는 일은 드물며 다른 사람들과 작업을 시작하자마자 서로의 작업과 충돌할 위험이 있다. 대표적인 예시가 두 사람이 같은 부분을 업데이트하려고 할 때이다. 동시에 코드의. 발생을 관리하고 결과적으로 작업 손실을 피할 수있는 메커니즘이 필요하다.</li> + <li>혼자 또는 다른 사람들과 함께 프로젝트를 수행 할 때 중앙 위치에 코드를 백업 할 수 있기 때문에 컴퓨터가 고장 나더라도 코드가 손실되지 않는다.</li> + <li>추후에 문제가 발견될 경우, 이전 버전을 찾게 될 수 있다. 우리는 이미 같은 파일의 다른 버전들을 생성함으로써 우리는 버전 컨트롤을 하고 있었을지도 모른다. 예를 들어, <code>myCode.js</code>, <code>myCode_v2.js</code>, <code>myCode_v3.js</code>, <code>myCode_final.js</code>, <code>myCode_really_really_final.js</code>, 등 이런식으로 말이다. 그러나 이런 방식은 에러에 취약하며 신뢰성이 떨어진다.</li> + <li>Different team members will commonly want to create their own separate versions of the code (called <strong>branches</strong> in Git), work on a new feature in that version, and then get it merged in a controlled manner (in GitHub we use <strong>pull requests</strong>) with the master version when they are done with it.</li> +</ul> + +<p>VCSes provide tools to meet the above needs. <a href="https://git-scm.com/">Git</a> is an example of a VCS, and <a href="https://github.com/">GitHub</a> is a web site + infrastructure that provides a Git server plus a number of really useful tools for working with git repositories individually or in teams, such as reporting issues with the code, reviewing tools, project management features such as assigning tasks and task statuses, and more.</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: Git is actually a <em>distributed</em> version control system, meaning that a complete copy of the repository containing the codebase is made on your computer (and everyone else's). You make changes to your own copy, and then push those changes back up to the server, where an administrator will decide whether to merge your changes with the master copy.</p> +</div> + +<h2 id="전제_조건">전제 조건</h2> + +<p>Git와 GitHub를 사용하려면, 다음과 같은 사양이 요구된다:</p> + +<ul> + <li>Git가 설치된 데스크탑 컴퓨터(<a href="https://git-scm.com/downloads">Git 설치 페이지</a>를 참고하라).</li> + <li>Git을 사용할 도구. 당신이 어떻게 일하고 싶은지에 따라 취향에 맞게 <a href="https://git-scm.com/downloads/guis/">Git GUI client</a> (GitHub Desktop, SourceTree, Git Kraken을 추천합니다) 와 터미널 중에 고르실 수 있습니다. GUI를 사용하더라도 기본적인 git 터미널 명령어들을 숙지하고 있다면 더 큰 도움이 될 것입니다.</li> + <li><a href="https://github.com/join">GitHub 계정</a>. 만일 계정이 없다면, 이 링크에서 계정을 만들 수 있다.</li> +</ul> + +<p>이 모듈에 필요한 전제 지식과 관련해서 웹개발, Git/Github, VCS에 관한 지식은 없어도 시작할 수 있다. 그러나 어느정도의 컴퓨터 소양과 코딩 능력이 뒷바침되면 repository에 코드를 저장해 놓을 수 있으므로 코딩 지식이 있으면 좋다.</p> + +<p>코딩 지식과 더불어 기초적인 용어에 대한 지식이 있으면 좋다. 예를 들어, 디렉토리를 이동하거나 파일생성, 그리고 시스템 <code>PATH</code>를 변경시키는것과 같은 기본적인 용어에 대한 지식이 있는 것이 추천된다.</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: Github is not the only site/toolset you can use with Git. There are other alternatives such as <a href="https://about.gitlab.com/">GitLab</a> that you could try, and you could also try setting your own Git server up and using it instead of GitHub. We've only stuck with GitHub in this course to provide a single way that works.</p> +</div> + +<h2 id="가이드">가이드</h2> + +<p>아래 링크들은 모두 외부 사이트로 연결된다. Mozilla는 Mozilla만의 독자적인 Git/Github 과정을 만드는 것을 목표로 하고 있으나 당장은 아래에 있는 항목들이 Github을 직접 해볼 수 있도록 도와줄 것이다.</p> + +<dl> + <dt><a href="https://guides.github.com/activities/hello-world/">Hello World (from GitHub)</a></dt> + <dd>This is a good place to start — this practical guide gets you to jump right into using GitHub, learning the basics of Git such as creating repositories and branches, making commits, and opening and merging pull requests.</dd> + <dt><a href="https://guides.github.com/introduction/git-handbook/">Git Handbook (from GitHub)</a></dt> + <dd>This Git Handbook goes into a little more depth, explaining what a VCS is, what a repository is, how the basic GitHub model works, Git commands and examples, and more.</dd> + <dt><a href="https://guides.github.com/activities/forking/">Forking Projects (from GitHub)</a></dt> + <dd>Forking projects is essential when you want to contribute to someone else's code. This guide explains how.</dd> + <dt><a href="https://help.github.com/en/articles/about-pull-requests">About Pull Requests (from GitHub)</a></dt> + <dd>A useful guide to managing pull requests, the way that your suggested code changes are delivered to people's repositories for consideration.</dd> + <dt><a href="https://guides.github.com/features/issues/">Mastering issues (from GitHub)</a></dt> + <dd>Issues are like a forum for your GitHub project, where people can ask questions and report problems, and you can manage updates (for example assigning people to fix issues, clarifying the issue, letting people know things are fixed). This articles gives you what you need to know about issues.</dd> +</dl> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: There is <strong>a lot more</strong> that you can do with Git and GitHub, but we feel that the above represents the minimum you need to know to start using Git effectively. As you get deeper into Git, you'll start to realise that it is easy to go wrong when you start using more complicated commands. Don't worry, even professional web developers find Git confusing sometimes, and often solve problems by searching for solutions on the web, or consulting sites like <a href="https://github.com/k88hudson/git-flight-rules">Flight rules for Git</a> and<a href="https://dangitgit.com/"> Dangit, git!</a></p> +</div> + +<h2 id="바깥_고리">바깥 고리</h2> + +<ul> + <li><a href="https://guides.github.com/introduction/flow/">Understanding the GitHub flow</a></li> + <li><a href="https://git-scm.com/docs">Git command list</a></li> + <li><a href="https://guides.github.com/features/mastering-markdown/">Mastering markdown</a> (the text format you write in on PR, issue comments, and <code>.md</code> files).</li> + <li><a href="https://guides.github.com/features/pages/">Getting Started with GitHub Pages</a> (how to publish demos and websites on GitHub).</li> + <li><a href="https://learngitbranching.js.org/">Learn Git branching</a></li> + <li><a href="https://github.com/k88hudson/git-flight-rules">Flight rules for Git</a> (a very useful compendium of ways to achieve specific things in Git, including how to correct things when you went wrong).</li> + <li> + <p><a href="https://dangitgit.com/">Dangit, git!</a> (another useful compendium, specifically of ways to correct things when you went wrong).</p> + </li> +</ul> diff --git a/files/ko/learn/tools_and_testing/index.html b/files/ko/learn/tools_and_testing/index.html new file mode 100644 index 0000000000..bbb3cb90ef --- /dev/null +++ b/files/ko/learn/tools_and_testing/index.html @@ -0,0 +1,31 @@ +--- +title: Tools and testing +slug: Learn/Tools_and_testing +translation_of: Learn/Tools_and_testing +--- +<div>{{LearnSidebar}}</div> + +<p class="summary">HTML, CSS, 자바스크립트와 같은 핵심 웹 기술들에 익숙해지고, 다양한 경험을 쌓고, 다양한 자원을 활용하고, 새로운 팁과 방법들을 배우면서, 여러분은 여러 종류의 도구들을 활용할 수 있게 될 겁니다. 미리 작성된 CSS 또는 자바스크립트 코드부터, 앱 테스트와 자동화 등. 여러분의 웹 프로젝트가 점점 커지고 복잡해지면 여러분은 이런 도구들과 신뢰성 있는 테스트를 필요로 할 것입니다. 이 파트에서는 이러한 도구들을 쓰거나 선택하기 위해 무엇을 알아야 하는지 알려줍니다.</p> + +<p>웹 산업은 복잡하기에 아름답습니다. 우리가 웹 사이트를 만드는데 쓰는 핵심 기술들은 상당히 안정적이지만, 이런 기술들에 기반하여 더욱 개발을 편리하게 해 주는 새로운 기능과 도구들이 계속해서 생겨나고 있습니다. 거기다 웹 표준, 크로스 브라우저 지원, 모바일 호환 및 장애인들을 위한 접근성까지도 신경써야 합니다.</p> + +<p>Working out what tools you should be using can be a difficult process, so we have written this set of articles to inform you of what types of tool are available, what they can do for you, and how to make use of the current industry favourites.</p> + +<div class="note"> +<p><strong>Note</strong>: Because new tools appear and old ones go out of fashion all the time, we have deliberately written this material to be as neutral as possible — we want to focus first and foremost on the general types of tasks these tools will help you accomplish, and keep prescribing specific tools to a minimum. We obviously need to show tool usage to demonstrate specific techniques, but be clear that we do not necessarily recommend these tools as the best or only way to do things — in most cases there are other ways, but we want to provide you with a clear methodology that works.</p> +</div> + +<h2 id="Learning_pathway">Learning pathway</h2> + +<p>You should really learn the basics of the core <a href="/en-US/docs/Learn/HTML">HTML</a>, <a href="/en-US/docs/Learn/CSS">CSS</a>, and <a href="/en-US/docs/Learn/JavaScript">JavaScript</a> languages first before attempting to use the tools detailed here. For example, you'll need to know the fundamentals of these languages before you start debugging problems in complex web code, or making effective use of JavaScript libraries, or writing tests and running them against your code using test runners, etc.</p> + +<p>You need a solid foundation first.</p> + +<h2 id="Modules">Modules</h2> + +<dl> + <dt>Real world web development tools (TBD)</dt> + <dd>In this module, we explore the different kinds of web development tools available. This includes reviewing the most common kinds of tasks you may be called on to solve, how they can fit together in a workflow, and the best tools currently avaiable for carrying out those tasks.</dd> + <dt><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing">Cross browser testing</a></dt> + <dd>This module looks specifically at the area of testing web projects across different browsers. Here we look identifying your target audience (e.g. what users, browsers and devices do you most need to worry about?), how to go about doing testing, the main issues that you'll face with different types of code and how to fix/mitigate those, what tools are most useful in helping you test and fix problems, and how to use automation to speed up testing.</dd> +</dl> diff --git a/files/ko/learn/web_기술/index.html b/files/ko/learn/web_기술/index.html new file mode 100644 index 0000000000..7a3621b92e --- /dev/null +++ b/files/ko/learn/web_기술/index.html @@ -0,0 +1,23 @@ +--- +title: Web 기술 +slug: Learn/Web_기술 +tags: + - Beginner + - WebMechanics +translation_of: Learn/Common_questions +--- +<p><span style="line-height: 1.5;">이것은 여러분이 웹 생태계를 이해할 수 있도록 충분히 설명해줍니다. 저희는 여러분이 필요한 정보를 작고, 세분화된 기술로 나누었습니다.</span></p> + +<p>{{NoteStart}}<em>Web 기술 </em>은 웹 생태계의 기술적인 측명이 아니라, <a href="/en-US/docs/Learn/skills/Infrastructure"><em>Infrastructure </em></a>범위의 기능에 집중합니다.{{NoteEnd}}</p> + +<h2 id="기본_스킬">기본 스킬</h2> + +<p>만약 웹이 익숙하지 않다면 여기서 시작하세요. 웹 용어의 이해를 돕기 위한 우리의 <a href="/en-US/docs/Glossary" style="line-height: 1.5;">glossary</a> 에 의지하는것도 제안합니다.</p> + +<h2 id="중급_스킬">중급 스킬</h2> + +<p>일단 웹이 익숙해지셨다면, 여러분이 탐구할 몇 가지 세부적인 것이 여기 있습니다:</p> + +<h2 id="고급_스킬">고급 스킬</h2> + +<p>만약 웹 제작을 경험해보셨다면, 여러분은 몇 가지 특수하거나 일반적이지 않은 기술들에 흥미를 가지실 것입니다.</p> diff --git a/files/ko/learn/접근성/html/index.html b/files/ko/learn/접근성/html/index.html new file mode 100644 index 0000000000..dae842fc92 --- /dev/null +++ b/files/ko/learn/접근성/html/index.html @@ -0,0 +1,537 @@ +--- +title: 'HTML: 접근성을 위한 기초' +slug: Learn/접근성/HTML +tags: + - HTML + - HTML 접근성 + - 스크린리더 + - 시멘틱 + - 시멘틱 웹 + - 시멘틱웹 + - 웹 접근성 + - 접근성 향상 +translation_of: Learn/Accessibility/HTML +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Accessibility/What_is_Accessibility","Learn/Accessibility/CSS_and_JavaScript", "Learn/Accessibility")}}</div> + +<p class="summary">HTML 요소가 늘 올바른 목적을 가지고 쓰이는지 확인하는 것만으로도, 수많은 웹 콘텐츠는 접근성이 향상됩니다. 이 문서에는 접근성을 최대한으로 보장하기 위해 HTML을 어떻게 사용해야 하는지 자세히 설명합니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">Prerequisites:</th> + <td>Basic computer literacy, a basic understanding of HTML (see <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML">Introduction to HTML</a>), and understanding of <a href="/en-US/docs/Learn/Accessibility/What_is_accessibility">what accessibility is</a>.</td> + </tr> + <tr> + <th scope="row">Objective:</th> + <td>To gain familiarity with what features of HTML have accessibility benefits, and how to use them appropriately in your web documents.</td> + </tr> + </tbody> +</table> + +<h2 id="HTML과_접근성">HTML과 접근성</h2> + +<p> </p> + +<p>HTML에 대해 더 많은 자료와 예제를 접하고, 더 많이 배우면 배울수록 당신은 의미론적 HTML(시멘틱 HTML, POSH 또는 Plain Old Semantic HTML라고 부르기도 합니다)을 사용하는 것이 중요하다는 공통 주제를 계속해서 접하게 될 것입니다. 이것은 가능한 올바른 목적으로 올바른 HTML 요소를 사용하는 것을 의미합니다.</p> + +<p>당신은 아마 이것이 왜 중요한지 의문을 가질 수 있을 것입니다. 당신은 CSS와 JavaScript 조합을 사용해 원하는 방식으로 HTML 요소들을 동작시킬 수 있기 때문입니다. 예를 들어 사이트에서 동영상을 제어하기 위한 버튼을 당신은 이렇게 마크업 할 수 있습니다.</p> + +<pre class="brush: html"><div>Play video</div></pre> + +<p>그러나 당신이 나중에 더 자세하게 배울수록, 작업에 올바른 HTML 요소를 사용하는 것이 많은 의미를 내포하고 있음을 깨닫게 될 것입니다.</p> + +<pre class="brush: html"><button>Play video</button></pre> + +<p>Not only do HTML <code><button></code>s have some suitable styling applied by default (which you will probably want to override), they also have built-in keyboard accessibility — they can be tabbed between, and activated using Return/Enter.</p> + +<p>Semantic HTML doesn't take longer to write than non-semantic (bad) markup if you do it consistently from the start of your project, and it also has other benefits beyond accessibility:</p> + +<ol> + <li><strong>Easier to develop with</strong> — as mentioned above, you get some functionality for free, plus it is arguably easier to understand.</li> + <li><strong>Better on mobile</strong> — semantic HTML is arguably lighter in file size than non-semantic spaghetti code, and easier to make responsive.</li> + <li><strong>Good for SEO</strong> — search engines give more importance to keywords inside headings, links, etc., than keywords included in non-semantic <code><div></code>s, etc., so your documents will be more findable by customers.</li> +</ol> + +<p>Let's get on and look at accessible HTML in more detail.</p> + +<div class="note"> +<p><strong>Note</strong>: It is a good idea to have a screenreader set up on your local computer, so you can do some testing of the examples shown below. See our <a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Accessibility#Screenreaders">Screenreaders guide</a> for more details.</p> +</div> + +<h2 id="Good_semantics">Good semantics</h2> + +<p>We've already talked about the importance of good semantics, and why we should use the right HTML element for the right job. This cannot be ignored, as it is one of the main places that accessibility is badly broken if not handled properly.</p> + +<p>Out there on the web, the truth is that people do some very strange things with HTML markup. Some abuses of HTML are due to legacy practices that have not been completely forgotten, and some are just plain ignorance. Whatever the case, you should replace such bad code wherever you see it, whenever you can.</p> + +<p>Sometimes you are not always in the position to get rid of bad markup — your pages might be generated by some kind of server-side framework that you don't have full control over, or you might have third party content on your page (such as ad banners) that you don't have control over.</p> + +<p>The goal isn't "all or nothing", however — every improvement you are able to make will help the cause of accessibility.</p> + +<h3 id="Text_content">Text content</h3> + +<p>One of the best accessibility aids a screenreader user can have is a good content structure of headings, paragraphs, lists, etc. A good semantic example might look something like the following:</p> + +<pre class="brush: html example-good line-numbers language-html"><code class="language-html"><span class="tag token"><span class="tag token"><span class="punctuation token"><</span>h1</span><span class="punctuation token">></span></span>My heading<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>h1</span><span class="punctuation token">></span></span> + +<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>p</span><span class="punctuation token">></span></span>This is the first section of my document.<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>p</span><span class="punctuation token">></span></span> + +<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>p</span><span class="punctuation token">></span></span>I'll add another paragraph here too.<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>p</span><span class="punctuation token">> + +<ol> + <li>Here is</li> + <li>a list for</li> + <li>you to read</li> +</ol></span></span> + +<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>h2</span><span class="punctuation token">></span></span>My subheading<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>h2</span><span class="punctuation token">></span></span> + +<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>p</span><span class="punctuation token">></span></span>This is the first subsection of my document. I'd love people to be able to find this content!<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>p</span><span class="punctuation token">></span></span> + +<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>h2</span><span class="punctuation token">></span></span>My 2nd subheading<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>h2</span><span class="punctuation token">></span></span> + +<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>p</span><span class="punctuation token">></span></span>This is the second subsection of my content. I think is more interesting than the last one.<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>p</span><span class="punctuation token">></span></span></code></pre> + +<p>We've prepared a version with longer text for you to try out with a screenreader (see <a href="http://mdn.github.io/learning-area/accessibility/html/good-semantics.html">good-semantics.html</a>). If you try navigating through this, you'll see that this is pretty easy to navigate:</p> + +<ol> + <li>The screenreader reads each header out as you progress through the content, notifying you what is a heading, what is a paragraph, etc.</li> + <li>It stops after each element, letting you go at whatever pace is comfortable for you.</li> + <li>You can jump to next/previous heading in many screenreaders.</li> + <li>You can also bring up a list of all headings in many screenreaders, allowing you to use them like a handy table of contents to find specific content.</li> +</ol> + +<p>People sometimes write headings, paragraphs, etc. using presentational HTML and line breaks, something like the following:</p> + +<pre class="brush: html example-bad line-numbers language-html"><code class="language-html"><span class="tag token"><span class="tag token"><span class="punctuation token"><</span>font</span> <span class="attr-name token">size</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>7<span class="punctuation token">"</span></span><span class="punctuation token">></span></span>My heading<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>font</span><span class="punctuation token">></span></span> +<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>br</span><span class="punctuation token">></span></span><span class="tag token"><span class="tag token"><span class="punctuation token"><</span>br</span><span class="punctuation token">></span></span> +This is the first section of my document. +<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>br</span><span class="punctuation token">></span></span><span class="tag token"><span class="tag token"><span class="punctuation token"><</span>br</span><span class="punctuation token">></span></span> +I'll add another paragraph here too. +<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>br</span><span class="punctuation token">></span><span class="tag token"><span class="punctuation token"><</span>br</span><span class="punctuation token">> +1. Here is +</span><span class="tag token"><span class="punctuation token"><</span>br</span><span class="punctuation token">></span><span class="tag token"><span class="punctuation token"><</span>br</span><span class="punctuation token">> +2. a list for +</span><span class="tag token"><span class="punctuation token"><</span>br</span><span class="punctuation token">></span><span class="tag token"><span class="punctuation token"><</span>br</span><span class="punctuation token">> +3. you to read +</span><span class="tag token"><span class="punctuation token"><</span>br</span><span class="punctuation token">></span><span class="tag token"><span class="punctuation token"><</span>br</span><span class="punctuation token">></span></span> +<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>font</span> <span class="attr-name token">size</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>5<span class="punctuation token">"</span></span><span class="punctuation token">></span></span>My subheading<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>font</span><span class="punctuation token">></span></span> +<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>br</span><span class="punctuation token">></span></span><span class="tag token"><span class="tag token"><span class="punctuation token"><</span>br</span><span class="punctuation token">></span></span> +This is the first subsection of my document. I'd love people to be able to find this content! +<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>br</span><span class="punctuation token">></span></span><span class="tag token"><span class="tag token"><span class="punctuation token"><</span>br</span><span class="punctuation token">></span></span> +<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>font</span> <span class="attr-name token">size</span><span class="attr-value token"><span class="punctuation token">=</span><span class="punctuation token">"</span>5<span class="punctuation token">"</span></span><span class="punctuation token">></span></span>My 2nd subheading<span class="tag token"><span class="tag token"><span class="punctuation token"></</span>font</span><span class="punctuation token">></span></span> +<span class="tag token"><span class="tag token"><span class="punctuation token"><</span>br</span><span class="punctuation token">></span></span><span class="tag token"><span class="tag token"><span class="punctuation token"><</span>br</span><span class="punctuation token">></span></span> +This is the second subsection of my content. I think is more interesting than the last one.</code></pre> + +<p>If you try our longer version out with a screenreader (see <a href="http://mdn.github.io/learning-area/accessibility/html/bad-semantics.html">bad-semantics.html</a>), you'll not have a very good experience — the screenreader hasn't got anything to use as signposts, so you can't retrieve a useful table of contents, and the whole page is seen as a single giant block, so it is just read out in one go, all at once.</p> + +<p>There are other issues too beyond accessibility — it is harder to style the content using CSS, or manipulate it with JavaScript for example, because there are no elements to use as selectors.</p> + +<h4 id="Using_clear_language">Using clear language</h4> + +<p>The language you use can also affect accessibility. In general you should use clear language that is not overly complex, and doesn't use unnecessary jargon or slang terms. This not only benefits people with cognitive or other disabilities; it benefits readers for whom the text is not written in their first language, younger people ... everyone in fact! Apart from this, you should try to avoid using language and characters that don't get read out clearly by the screenreader. For example:</p> + +<ul> + <li>Don't use dashes if you can avoid it. Instead of writing 5–7, write 5 to 7.</li> + <li>Expand abbreviations — instead of writing Jan, write January.</li> + <li>Expand acronyms, at least once or twice. Instead of writing HTML in the first instance, write Hypertext Markup Language.</li> +</ul> + +<h3 id="Page_layouts">Page layouts</h3> + +<p>In the bad old days, people used to create page layouts using HTML tables — using different table cells to contain the header, footer, side bar, main content column, etc. This is not a good idea because a screenreader will likely give out confusing readouts, especially if the layout is complex and has many nested tables.</p> + +<p>Try our example <a href="http://mdn.github.io/learning-area/accessibility/html/table-layout.html">table-layout.html</a> example, which looks something like this:</p> + +<pre class="brush: html"><table width="1200"> + <!-- main heading row --> + <tr id="heading"> + <td colspan="6"> + + <h1 align="center">Header</h1> + + </td> + </tr> + <!-- nav menu row --> + <tr id="nav" bgcolor="#ffffff"> + <td width="200"> + <a href="#" align="center">Home</a> + </td> + <td width="200"> + <a href="#" align="center">Our team</a> + </td> + <td width="200"> + <a href="#" align="center">Projects</a> + </td> + <td width="200"> + <a href="#" align="center">Contact</a> + </td> + <td width="300"> + <form width="300"> + <input type="search" name="q" placeholder="Search query" width="300"> + </form> + </td> + <td width="100"> + <button width="100">Go!</button> + </td> + </tr> + <!-- spacer row --> + <tr id="spacer" height="10"> + <td> + + </td> + </tr> + <!-- main content and aside row --> + <tr id="main"> + <td id="content" colspan="4" bgcolor="#ffffff"> + + <!-- main content goes here --> + </td> + <td id="aside" colspan="2" bgcolor="#ff80ff" valign="top"> + <h2>Related</h2> + + <!-- aside content goes here --> + + </td> + </tr> + <!-- spacer row --> + <tr id="spacer" height="10"> + <td> + + </td> + </tr> + <!-- footer row --> + <tr id="footer" bgcolor="#ffffff"> + <td colspan="6"> + <p>©Copyright 2050 by nobody. All rights reversed.</p> + </td> + </tr> + </table></pre> + +<p>If you try to navigate this using a screenreader, it will probably tell you that there's a table to be looked at (although some screenreaders can guess the difference between table layouts and data tables). You'll then likely (depending on which screenreader you're using) have to go down into the table as an object and look at its features separately, then get out of the table again to carry on navigating the content.</p> + +<p>Table layouts are a relic of the past — they made sense back when CSS support was not widespread in browsers, but they create confusion for screenreader users, as well as being bad for many other reasons (abuse of tables, arguably requires more markup, make designs more inflexible). Don't do it!</p> + +<p>You can verify these claims by comparing your previous experience with a <a href="http://mdn.github.io/learning-area/html/introduction-to-html/document_and_website_structure/">more modern website structure example</a>, which could look something like this:</p> + +<pre class="brush: html"><header> + <h1>Header</h1> +</header> + +<nav> + <!-- main navigation in here --> +</nav> + +<!-- Here is our page's main content --> +<main> + + <!-- It contains an article --> + <article> + <h2>Article heading</h2> + + <!-- article content in here --> + </article> + + <aside> + <h2>Related</h2> + + <!-- aside content in here --> + </aside> + +</main> + +<!-- And here is our main footer that is used across all the pages of our website --> + +<footer> + <!-- footer content in here --> +</footer></pre> + +<p>If you try our more modern structure example with a screenreader, you'll see that the layout markup no longer gets in the way and confuses the content readout. It is also much leaner and smaller in terms of code size, which means easier to maintain code, and less bandwidth for the user to download (particularly prevalent for those on slow connections).</p> + +<p>Another consideration when creating layouts is using HTML5 semantic elements as seen in the above example (see <a href="/en-US/docs/Web/HTML/Element#Content_sectioning">content sectioning</a>) — you can create a layout using only nested {{htmlelement("div")}} elements, but it is better to use appropriate sectioning elements to wrap your main navigation ({{htmlelement("nav")}}), footer ({{htmlelement("footer")}}), repeating content units ({{htmlelement("article")}}), etc. These provide extra semantics for screenreaders (and other tools) to give user extra clues about the content they are navigating (see <a href="http://www.weba11y.com/blog/2016/04/22/screen-reader-support-for-new-html5-section-elements/">Screen Reader Support for new HTML5 Section Elements</a> for an idea of what screen reader support is like).</p> + +<div class="note"> +<p><strong>Note</strong>: As well as your content having good semantics and an attractive layout, it should make logical sense in its source order — you can always place it where you want using CSS later on, but you should get the source order right to start with, so what screenreader users get read out to them will make sense.</p> +</div> + +<h3 id="UI_controls">UI controls</h3> + +<p>By UI controls, we mean the main parts of web documents that users interact with — most commonly buttons, links, and form controls. In this section we'll look at the basic accessibility concerns to be aware of when creating such controls. Later articles on WAI-ARIA and multimedia will look at other aspects of UI accessibility.</p> + +<p>One key aspect to the accessibility of UI controls is that by default, browsers allow them to be manipulated by the keyboard. You can try this out using our <a href="http://mdn.github.io/learning-area/tools-testing/cross-browser-testing/accessibility/native-keyboard-accessibility.html">native-keyboard-accessibility.html</a> example (see the <a href="https://github.com/mdn/learning-area/blob/master/tools-testing/cross-browser-testing/accessibility/native-keyboard-accessibility.html">source code</a>) — open this in a new tab, and try pressing the tab key; after a few presses, you should see the tab focus start to move through the different focusable elements; the focused elements are given a highlighted default style in every browser (it differs slightly between different browsers) so that you can tell what element is focused.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14215/button-focused-unfocused.png" style="border-style: solid; border-width: 1px; display: block; height: 39px; margin: 0px auto; width: 288px;"></p> + +<p>You can then press Enter/Return to follow a focused link or press a button (we've included some JavaScript to make the buttons alert a message), or start typing to enter text in a text input (other form elements have different controls, for example the {{htmlelement("select")}} element can have its options displayed and cycled between using the up and down arrow keys).</p> + +<div class="note"> +<p><strong>Note</strong>: Different browsers may have different keyboard control options available. See <a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Accessibility#Using_native_keyboard_accessibility">Using native keyboard accessibility</a> for more details.</p> +</div> + +<p>You essentially get this behavior for free, just by using the appropriate elements, e.g.</p> + +<pre class="brush: html example-good"><h1>Links</h1> + +<p>This is a link to <a href="https://www.mozilla.org">Mozilla</a>.</p> + +<p>Another link, to the <a href="https://developer.mozilla.org">Mozilla Developer Network</a>.</p> + +<h2>Buttons</h2> + +<p> + <button data-message="This is from the first button">Click me!</button> + <button data-message="This is from the second button">Click me too!</button> + <button data-message="This is from the third button">And me!</button> +</p> + +<h2>Form</h2> + +<form> + <div> + <label for="name">Fill in your name:</label> + <input type="text" id="name" name="name"> + </div> + <div> + <label for="age">Enter your age:</label> + <input type="text" id="age" name="age"> + </div> + <div> + <label for="mood">Choose your mood:</label> + <select id="mood" name="mood"> + <option>Happy</option> + <option>Sad</option> + <option>Angry</option> + <option>Worried</option> + </select> + </div> +</form></pre> + +<p>This means using links, buttons, form elements, and labels appropriately (including the {{htmlelement("label")}} element for form controls).</p> + +<p>However, it is again the case that people sometimes do strange things with HTML. For example, you sometimes see buttons marked up using {{htmlelement("div")}}s, for example:</p> + +<pre class="brush: html example-bad"><div data-message="This is from the first button">Click me!</div> +<div data-message="This is from the second button">Click me too!</div> +<div data-message="This is from the third button">And me!</div></pre> + +<p>But using such code is not advised — you immediately lose the native keyboard accessibility you would have had if you'd just used {{htmlelement("button")}} elements, plus you don't get any of the default CSS styling that buttons get.</p> + +<h4 id="Building_keyboard_accessibility_back_in">Building keyboard accessibility back in</h4> + +<p>Adding such advantages back in takes a bit of work (you can an example code in our <a class="external external-icon" href="http://mdn.github.io/learning-area/tools-testing/cross-browser-testing/accessibility/fake-div-buttons.html">fake-div-buttons.html</a> example — also see the <a class="external external-icon" href="https://github.com/mdn/learning-area/blob/master/tools-testing/cross-browser-testing/accessibility/fake-div-buttons.html">source code</a>). Here we've given our fake <code><div></code> buttons the ability to be focused (including via tab) by giving each one the attribute <code>tabindex="0"</code>:</p> + +<pre class="brush: html"><div data-message="This is from the first button" tabindex="0">Click me!</div> +<div data-message="This is from the second button" tabindex="0">Click me too!</div> +<div data-message="This is from the third button" tabindex="0">And me!</div></pre> + +<p>Basically, the {{htmlattrxref("tabindex")}} attribute is primarily intended to allow tabbable elements to have a custom tab order (specified in positive numerical order), instead of just being tabbed through in their default source order. This is nearly always a bad idea, as it can cause major confusion. Use it only if you really need to, for example if the layout shows things in a very different visual order to the source code, and you want to make things work more logically. There are two other options for <code>tabindex</code>:</p> + +<ul> + <li><code>tabindex="0"</code> — as indicated above, this value allows elements that are not normally tabbable to become tabbable. This is the most useful value of <code>tabindex</code>.</li> + <li><code>tabindex="-1"</code> — this allows not normally tabbable elements to receive focus programmatically, e.g. via JavaScript, or as the target of links. </li> +</ul> + +<p>Whilst the above addition allows us to tab to the buttons, it does not allow us to activate them via the Enter/Return key. To do that, we had to add the following bit of JavaScript trickery:</p> + +<pre class="brush: js line-numbers language-js"><code class="language-js">document<span class="punctuation token">.</span>onkeydown <span class="operator token">=</span> <span class="keyword token">function</span><span class="punctuation token">(</span>e<span class="punctuation token">)</span> <span class="punctuation token">{</span> + <span class="keyword token">if</span><span class="punctuation token">(</span>e<span class="punctuation token">.</span>keyCode <span class="operator token">===</span> <span class="number token">13</span><span class="punctuation token">)</span> <span class="punctuation token">{</span> <span class="comment token">// The Enter/Return key</span> + document<span class="punctuation token">.</span>activeElement<span class="punctuation token">.</span><span class="function token">click</span><span class="punctuation token">(</span><span class="punctuation token">)</span><span class="punctuation token">;</span> + <span class="punctuation token">}</span> +<span class="punctuation token">}</span><span class="punctuation token">;</span></code></pre> + +<p>Here we add a listener to the <code>document</code> object to detect when a button has been pressed on the keyboard. We check what button was pressed via the event object's <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode">keyCode</a></code> property; if it is the keycode that matches Return/Enter, we run the function stored in the button's <code>onclick</code> handler using <code>document.activeElement.click()</code>. <code><a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/activeElement">activeElement</a></code> gives us the element that is currently focused on the page.</p> + +<p>This is a lot of extra hassle to build the functionality back in. And there's bound to be other problems with it. <strong>Better to just use the right element for the right job in the first place.</strong></p> + +<h4 id="Meaningful_text_labels">Meaningful text labels</h4> + +<p>UI control text labels are very useful to all users, but getting them right is particularly important to users with disabilities.</p> + +<p>You should make sure that your button and link text labels are understandable and distinctive. Don't just use "Click here" for your labels, as screenreader users sometimes get up a list of buttons and form controls. The following screenshot shows our controls being listed by VoiceOver on Mac.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14335/voiceover-formcontrols.png" style="display: block; height: 604px; margin: 0px auto; width: 802px;"></p> + +<p>Make sure your labels make sense out of context, read on their own, as well as in the context of the paragraph they are in. For example, the following shows an example of good link text:</p> + +<pre class="brush: html example-good"><p>Whales are really awesome creatures. <a href="whales.html">Find out more about whales</a>.</p></pre> + +<p>but this is bad link text:</p> + +<pre class="brush: html example-bad"><p>Whales are really awesome creatures. To find more out about whales, <a href="whales.html">click here</a>.</p></pre> + +<div class="note"> +<p><strong>Note</strong>: You can find a lot more about link implementation and best practices in our <a href="/en-US/docs/Learn/HTML/Introduction_to_HTML/Creating_hyperlinks">Creating hyperlinks</a> article. You can also see some good and bad examples at <a href="http://mdn.github.io/learning-area/accessibility/html/good-links.html">good-links.html</a> and <a href="http://mdn.github.io/learning-area/accessibility/html/bad-links.html">bad-links.html</a>.</p> +</div> + +<p>Form labels are also important, for giving you a clue what you need to enter into each form input. The following seems like a reasonable enough example:</p> + +<pre class="brush: html example-bad">Fill in your name: <input type="text" id="name" name="name"></pre> + +<p>However, this is not so useful for disabled users. There is nothing in the above example to associate the label unambiguously with the form input, and make it clear how to fill it in if you cannot see it. If you access this with some screenreaders, you may only be given a description along the lines of "edit text".</p> + +<p>The following is a much better example:</p> + +<pre class="brush: html example-good"><div> + <label for="name">Fill in your name:</label> + <input type="text" id="name" name="name"> +</div></pre> + +<p>With the code like this, the label will be clearly associated with the input; the description will be more like "Fill in your name: edit text".</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14337/voiceover-good-form-label.png" style="display: block; margin: 0 auto;"></p> + +<p>As an added bonus, in most browsers associating a label with a form input means that you can click the label to select/activate the form element. This gives the input a bigger hit area, making it easier to select.</p> + +<div class="note"> +<p><strong>Note</strong>: you can see some good and bad form examples in <a href="http://mdn.github.io/learning-area/accessibility/html/good-form.html">good-form.html</a> and <a href="http://mdn.github.io/learning-area/accessibility/html/bad-form.html">bad-form.html</a>.</p> +</div> + +<h2 id="Accessible_data_tables">Accessible data tables</h2> + +<p>A basic data table can be written with very simple markup, for example:</p> + +<pre class="brush: html"><table> + <tr> + <td>Name</td> + <td>Age</td> + <td>Gender</td> + </tr> + <tr> + <td>Gabriel</td> + <td>13</td> + <td>Male</td> + </tr> + <tr> + <td>Elva</td> + <td>8</td> + <td>Female</td> + </tr> + <tr> + <td>Freida</td> + <td>5</td> + <td>Female</td> + </tr> +</table></pre> + +<p>But this has problems — there is no way for a screenreader user to associate rows or columns together as groupings of data. To do this you need to know what the header rows are, and if they are heading up rows, columns, etc. This can only be done visually for the above table (see <a href="http://mdn.github.io/learning-area/accessibility/html/bad-table.html">bad-table.html</a> and try the example out yourself).</p> + +<p>Now have a look at our <a href="https://github.com/mdn/learning-area/blob/master/css/styling-boxes/styling-tables/punk-bands-complete.html">punk bands table example</a> — you can see a few accessibility aids at work here:</p> + +<ul> + <li>Table headers are defined using {{htmlelement("th")}} elements — you can also specify if they are headers for rows or columns using the <code>scope</code> attribute. This gives you complete groups of data that can be consumed by screen readers as single units.</li> + <li>The {{htmlelement("caption")}} element and <code><table></code> <code>summary</code> attribute both do similar jobs — they act as alt text for a table, giving a screen reader user a useful quick summary of the table's contents. <code><caption></code> is generally preferred as it makes it's content accessible to sighted users too, who might also find it useful. You don't really need both.</li> +</ul> + +<div class="note"> +<p><strong>Note</strong>: See our <a href="/en-US/docs/Learn/HTML/Tables/Advanced">HTML table advanced features and accessibility</a> article for some more details around accessible data tables.</p> +</div> + +<h2 id="Text_alternatives">Text alternatives</h2> + +<p>Whereas textual content is inherently accessible, the same cannot necessarily be said for multimedia content — image/video content cannot be seen by visually-impaired people, and audio content cannot be heard by hearing-impaired people. We'll cover video and audio content in detail in the Accessible multimedia article later on, but for this article we'll look accessibility for the humble {{htmlelement("img")}} element.</p> + +<p>We have a simple example written up, <a href="http://mdn.github.io/learning-area/accessibility/html/accessible-image.html">accessible-image.html</a>, which features four copies of the same image:</p> + +<pre><img src="dinosaur.png"> + +<img src="dinosaur.png" + alt="A red Tyrannosaurus Rex: A two legged dinosaur standing upright like a human, with small arms, and a large head with lots of sharp teeth."> + +<img src="dinosaur.png" + alt="A red Tyrannosaurus Rex: A two legged dinosaur standing upright like a human, with small arms, and a large head with lots of sharp teeth." + title="The Mozilla red dinosaur"> + + +<img src="dinosaur.png" aria-labelledby="dino-label"> + +<p id="dino-label">The Mozilla red Tyrannosaurus Rex: A two legged dinosaur standing upright like a human, with small arms, and a large head with lots of sharp teeth.</p> +</pre> + +<p>The first image, when viewed by a screen reader, doesn't really offer the user much help — VoiceOver for example reads out "/dinosaur.png, image". It reads out the filename to try to provide some help. In this example the user will at least know it is a dinosaur of some kind, but often files may be uploaded with machine generated file names (e.g. from a digital camera) and these file names would likely provide no context to the image's content.</p> + +<div class="note"> +<p><strong>Note</strong>: This is why you should never include text content inside an image — screen readers simply can't access it. There are other disadvantages too — you can't select it and copy/paste it. Just don't do it!</p> +</div> + +<p>When a screen reader encounters the second image, it reads out the full alt attribute — "A red Tyrannosaurus Rex: A two legged dinosaur standing upright like a human, with small arms, and a large head with lots of sharp teeth.".</p> + +<p>This highlights the importance of not only using meaningful file names in case so-called <strong>alt text</strong> is not available, but also making sure that alt text is provided in <code>alt</code> attributes wherever possible. Note that the contents of the <code>alt</code> attribute should always provide a direct representation of the image and what it conveys visually. Any personal knowledge or extra description shouldn't be included here, as it is not useful for people who have not come across the image before.</p> + +<p>One thing to consider is whether your images have meaning inside your content, or whether they are purely for visual decoration, so have no meaning. If they are decorational, it is better to just include them in the page as CSS background images.</p> + +<div class="note"> +<p><strong>Note</strong>: Read <a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Images_in_HTML">Images in HTML</a> and <a href="/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images">Responsive images</a> for a lot more information about image implementation and best practices.</p> +</div> + +<p>If you do want to provide extra contextual information, you should put it in the text surrounding the image, or inside a <code>title</code> attribute, as shown above. In this case, most screenreaders will read out the alt text, the title attribute, and the filename. In addition, browsers display title text as tooltips when moused over.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14333/title-attribute.png" style="display: block; margin: 0 auto;"></p> + +<p>Let's have another quick look at the fourth method:</p> + +<pre class="brush: html"><img src="dinosaur.png" aria-labelledby="dino-label"> + +<p id="dino-label">The Mozilla red Tyrannosaurus ... </p></pre> + +<p>In this case, we are not using the <code>alt</code> attribute at all — instead, we have presented our description of the image as a regular text paragraph, given it an <code>id</code>, and then used the <code>aria-labelledby</code> attribute to refer to that <code>id</code>, which causes screenreaders to use that paragraph as the alt text/label for that image. This is especially useful if you want to use the same text as a label for multiple images — something that isn't possible with <code>alt</code>.</p> + +<div class="note"> +<p><strong>Note</strong>: <code>aria-labelledby</code> is part of the <a href="https://www.w3.org/TR/wai-aria-1.1/">WAI-ARIA</a> spec, which allows developers to add in extra semantics to their markup to improve screenreader accessibility where needed. To find out more about how it works, read our <a href="/en-US/docs/Learn/Accessibility/WAI-ARIA_basics">WAI-ARIA Basics</a> article.</p> +</div> + +<h3 id="Other_text_alternative_mechanisms">Other text alternative mechanisms</h3> + +<p>Images also have another mechanisms available for providing descriptive text. For example, there is a <code>longdesc</code> attribute that is meant to point to a separate web document containing an extended description of the image, for example:</p> + +<pre class="brush: html"><img src="dinosaur.png" longdesc="dino-info.html"></pre> + +<p>This sounds like a good idea, especially for infographics like big charts with lots of information on that could perhaps be represented as an accessible data table instead (see previous section). However, <code>longdesc</code> is not supported consistently by screenreaders, and the content is completely inaccessible to non-screenreader users. It is arguably much better to include the long description on the same page as the image, or link to it with a regular link.</p> + +<p>HTML5 includes two new elements — {{htmlelement("figure")}} and {{htmlelement("figcaption")}} — which are supposed to associate a figure of some kind (it could be anything, not necessarily an image) with a figure caption:</p> + +<pre class="brush: html"><figure> + <img src="dinosaur.png" alt="The Mozilla Tyrannosaurus"> + <figcaption>A red Tyrannosaurus Rex: A two legged dinosaur standing upright like a human, with small arms, and a large head with lots of sharp teeth.</figcaption> +</figure></pre> + +<p>Unfortunately, most screenreaders don't seem to associate figure captions with their figures yet, but the element structure is useful for CSS styling, plus it provides a way to place a description of the image next to it in the source.</p> + +<h3 id="Empty_alt_attributes">Empty alt attributes</h3> + +<pre class="brush: html"><h3> + <img src="article-icon.png" alt=""> + Tyrannosaurus Rex: the king of the dinosaurs +</h3></pre> + +<p>There may be times where an image is included in a page's design, but its primary purpose is for visual decoration. You'll notice in the code example above that the image's <code>alt</code> attribute is empty — this is to make screen readers recognize the image, but not attempt to describe the image (instead they'd just say "image", or similar).</p> + +<p>The reason to use an empty <code>alt</code> instead of not including it is because many screen readers announce the whole image URL if no <code>alt</code> is provided. In the above example, the image is acting as a visual decoration to the heading its associated with. In cases like this, and in cases where an image is only decoration and has no content value, you should put an empty <code>alt</code> on your images. Another alternative is to use the aria role attribute role="presentation" — this also stops screens readers from reading out alternative text.</p> + +<div class="note"> +<p><strong>Note</strong>: if possible you should use CSS to display images that are only decoration.</p> +</div> + +<h2 id="Summary">Summary</h2> + +<p>You should now be well-versed in writing accessible HTML for most occasions. Our WAI-ARIA basics article will also fill in some gaps in this knowledge, but this article has taken care of the basics. Next up we'll explore CSS and JavaScript, and how accessibility is affected by their good or bad use.</p> + +<p>{{PreviousMenuNext("Learn/Accessibility/What_is_Accessibility","Learn/Accessibility/CSS_and_JavaScript", "Learn/Accessibility")}}</p> + +<p> </p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Accessibility/What_is_accessibility">What is accessibility?</a></li> + <li><a href="/en-US/docs/Learn/Accessibility/HTML">HTML: A good basis for accessibility</a></li> + <li><a href="/en-US/docs/Learn/Accessibility/CSS_and_JavaScript">CSS and JavaScript accessibility best practices</a></li> + <li><a href="/en-US/docs/Learn/Accessibility/WAI-ARIA_basics">WAI-ARIA basics</a></li> + <li><a href="/en-US/docs/Learn/Accessibility/Multimedia">Accessible multimedia</a></li> + <li><a href="/en-US/docs/Learn/Accessibility/Mobile">Mobile accessibility</a></li> + <li><a href="/en-US/docs/Learn/Accessibility/Accessibility_troubleshooting">Accessibility troubleshooting</a></li> +</ul> + +<p> </p> diff --git a/files/ko/learn/접근성/index.html b/files/ko/learn/접근성/index.html new file mode 100644 index 0000000000..01c9c2e2bb --- /dev/null +++ b/files/ko/learn/접근성/index.html @@ -0,0 +1,59 @@ +--- +title: 접근성 +slug: Learn/접근성 +tags: + - ARIA + - CSS + - HTML + - JavaScript + - 랜딩 + - 모듈 + - 문서 + - 배우기 + - 비기너 + - 접근성 +translation_of: Learn/Accessibility +--- +<div>{{LearnSidebar}}</div> + +<p class="summary"><font><font>웹 개발자가 되기위해서 HTML, CSS 및 JavaScript를 배우는 것이 필요하지만 배운 지식을 효과적으로 사용하기위해서는 지식이상의 기술이 필요로 합니다. 이 기술을 사용해서 웹사이트에 접근하려는 모든 사용자를 차별없이 접근할수 있도록 해야합니다. 이를 위하여</font><font> 모범 사례(</font></font><a href="https://developer.mozilla.org/ko/docs/Learn/HTML"><font><font>HTML</font></font></a><font><font>, </font></font><a href="https://developer.mozilla.org/ko/docs/Learn/CSS"><font><font>CSS</font></font></a><font><font> 및 </font></font><a href="https://developer.mozilla.org/ko/docs/Learn/JavaScript"><font><font>JavaScript</font></font></a><font><font> 항목에서 설명) </font><font>를 준수하고 </font></font><a href="https://developer.mozilla.org/ko/docs/Learn/Tools_and_testing/Cross_browser_testing"><font><font>브라우저 호환성 테스트를 거치며</font></font></a><font><font> 처음부터 접근성을 고려해야합니다. </font><font>이 문서에서는 후자에 대해 자세히 다룰 것입니다.</font></font></p> + +<h2 id="선결조건">선결조건</h2> + +<p><font><font>이 문서를 최대한 활용하려면 최소한 </font></font><a href="https://developer.mozilla.org/ko/docs/Learn/HTML"><font><font>HTML</font></font></a><font><font>, </font></font><a href="https://developer.mozilla.org/ko/docs/Learn/CSS"><font><font>CSS</font></font></a><font><font> 및 </font></font><a href="https://developer.mozilla.org/ko/docs/Learn/JavaScript"><font><font>JavaScript</font></font></a><font><font> 항목 </font><font>중 처음 두 문서를 </font><font>통해 작업하거나 또는 접근성 문서와 관련된 기술을 통해 개선해 나가는것이 좋습니다. </font></font></p> + +<div class="note"> +<p><strong>Note</strong>: <strong><font><font>참고</font></font></strong><font><font> : 당신은 당신이 당신의 자신의 파일을 생성 할 수있는 기능이없는 컴퓨터 / 태블릿 / 다른 장치에서 작업하는 경우, 당신은 </font></font><a href="http://jsbin.com/">JSBin</a> 또는 <a href="https://thimble.mozilla.org/">Thimble</a> <font><font>같은 온라인 코딩 프로그램에서 코드 예제의 대부분을 테스트 할수 있습니다.</font></font></p> +</div> + +<h2 id="가이드">가이드</h2> + +<dl> + <dt><a href="/ko/docs/Learn/Accessibility/What_is_accessibility">접근성이란?</a></dt> + <dd>이 문서에서는 접근성이 실제로 무엇인지 자세히 살펴보는 것으로 모듈을 시작합니다. 여기에는 고려해야 할 사람의 그룹, 웹과 상호 작용하는 데 사용하는 서로 다른 도구 및 접근성 워크 플로우를 개발하는 방법이 포함됩니다.</dd> + <dt><a href="/ko/docs/Learn/Accessibility/HTML">HTML: 접근성을 위한 좋은기초</a></dt> + <dd>항상 올바른 HTML요소를 올바른 용도로 사용하는 것만으로 수많은 웹 콘텐츠에 접근 할 수 있습니다. 이 문서는 접근성을 극대화하기 위해 HTML을 사용하는 방법을 자세히 살펴봅니다.</dd> + <dt><a href="/ko/docs/Learn/Accessibility/CSS_and_JavaScript">CSS 와 JavaScript의 접근성 모범 사례</a></dt> + <dd>또한, CSS 와 JavaScript를 적절히 사용하면 접근성 높은 웹 경험을 줄수도 있지만 , 만약 잘못 사용될 경우 접근성을 크게 해칠 수 있다. 이 문서에서는 복잡한 컨텐츠도 가능한 액세스 할 수 있도록 하기 위해 고려해야 할 몇가지 CSS 및 JavaScript모범 사례를 간략히 설명합니다.</dd> + <dt><a href="/ko/docs/Learn/Accessibility/WAI-ARIA_basics">WAI-ARIA 기초</a></dt> + <dd>이전 문서에 이어, 시맨틱하지 못한 HTML과 동적 자바 스크립트로 업데이트되는 컨텐츠를 포함하는 복잡한 UI를 제어 하는 것은 어려울 수 있습니다. WAI-ARIA는 브라우저와 보조 기술이 사용자에게 상황을 알려 주는 데 사용할 수 있는 시맨틱한 요소를 추가하여 이러한 문제를 해결하는 기술이다. 여기서는 접근성을 향상시키기 위해 기본적인 수준에서 이 기능을 사용하는 방법을 보여 줍니다.</dd> + <dt><a href="/ko/docs/Learn/Accessibility/Multimedia">멀티미디어 접근성</a></dt> + <dd>접근성 문제를 야기할 수 있는 또 다른 범주의 콘텐츠 즉 멀티 미디어 . 비디오, 오디오 및 이미지 콘텐츠에 적절한 대체텍스트를 제공해서 보조 기술과 사용자가 이해할 수 있도록 해야 한다. 이 글은 그 방법을 보여 준다.</dd> + <dt><a href="/ko/docs/Learn/Accessibility/Mobile">모바일 접근성</a></dt> + <dd>모바일 기기를 이용한 웹 접근이 매우 널리 사용되고 있고 iOS및 Android와 같은 유명한 플랫폼에서 액세스가 가능한 툴을 사용하는 경우, 이러한 플랫폼에서 웹 콘텐츠를 접근 할 수 있는지를 고려해야 합니다. 이 자료에서는 모바일 접근성 고려 사항에 대해 살펴봅니다.</dd> +</dl> + +<h2 id="평가">평가</h2> + +<dl> + <dt><a href="/ko/docs/Learn/Accessibility/Accessibility_troubleshooting">접근성 문제 해결 </a></dt> + <dd>평가에서는 진단 및 해결해야 하는 다양한 접근성 문제가 포함된 간단한 사이트를 제공합니다.</dd> +</dl> + +<h2 id="참고_항목">참고 항목</h2> + +<ul> + <li><a href="https://egghead.io/courses/start-building-accessible-web-applications-today">Start Building Accessible Web Applications Today</a> — an excellent series of video tutorials by Marcy Sutton.</li> + <li><a href="https://dequeuniversity.com/resources/">Deque University resources</a> — includes code examples, screen reader references, and other useful resources.</li> + <li><a href="http://webaim.org/resources/">WebAIM resources</a> — includes guides, checklists, tools, and more.</li> +</ul> diff --git a/files/ko/learn/접근성/what_is_accessibility/index.html b/files/ko/learn/접근성/what_is_accessibility/index.html new file mode 100644 index 0000000000..67f4b6d302 --- /dev/null +++ b/files/ko/learn/접근성/what_is_accessibility/index.html @@ -0,0 +1,205 @@ +--- +title: What is accessibility? +slug: Learn/접근성/What_is_accessibility +translation_of: Learn/Accessibility/What_is_accessibility +--- +<p>{{LearnSidebar}}</p> + +<p>{{NextMenu("Learn/Accessibility/HTML", "Learn/Accessibility")}}</p> + +<p>이 글에서는 접근성이 실제로 무엇인지 자세히 살펴보기로 합니다. 이 글에는 웹에서 고려해야 할 사람의 그룹, 웹과 상호 작용하는 데 사용하는 서로 다른 도구 및 접근성 개발 워크 플로우를 포함됩니다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">선행지식:</th> + <td>기본적인 컴퓨터 사용 능력, HTML과 CSS에 대한 기본적인 이해.</td> + </tr> + <tr> + <th scope="row">목표:</th> + <td>접근성과 친해지기. 웹 개발자로서 접근성에어떻게 영향을 미치는지 알아보기</td> + </tr> + </tbody> +</table> + +<h2 id="그렇다면_접근성이란_무엇일까요">그렇다면 접근성이란 무엇일까요?</h2> + +<p>접근성은 가능한 한 많은 사람이 웹 사이트를 사용할 수 있도록 하는 방법으로, 통상적으로 장애인만을 대상으로 한다고 생각하지만 실제로는 모바일 장치를 사용하는 사람이나 느린 네트워크 연결을 사용하는 사람들도 포함하고 있습니다.</p> + +<p>접근성을 모든 사람을 동일하게 대하고, 그들의 능력이나 상황에 상관 없이 그들에게 같은 기회를 주는 것으로 생각할 수도 있습니다. 휠체어에 있기 때문에 누군가를 물리적 건물에서 제외시키는 것이 옳지 않은 것과 같은 방식으로(공공 건물에는 일반적으로 휠체어 경사로나 엘리베이터가 있기 때문에), 휴대 전화를 사용하지 않는 사람을 웹 사이트에서 제외시키는 것도 옳지 않다. 우리는 모두 다르지만, 모두 인간이기 때문에, 동일한 권리를 갖고 있다.</p> + +<p>접근성은 당연히 지켜져야 할 일이지만 일부 국가에서는 법의 일부이기도 하며, 서비스 사용이나 제품 구매가 불가능했던 사람들을 불러모아 중요한 소비자들로 만들수도 있습니다.</p> + +<p>접근성 및 이에 따른 모범 사례는 다음과 같은 모든 사람에게 도움이 될 수 있습니다.</p> + +<ul> + <li>시맨틱한 HTML (접근성이 향상된)은 SEO 향상시켜, 사이트를 찾기 쉽고 시장성이 있도록 해준다.</li> + <li>접근성에 대해 고려하는것은 좋은 윤리적인 도덕 관념을 보여 주는데, 이것은 서비스의 대중적인 이미지를 개선시킵니다.</li> + <li>접근성을 향상시키는 다른 좋은 방법은 당신의 사이트를 휴대폰 사용자, 낮은 네트워크 속도의 사용자등 다른 여러 사용자가 사용하기 쉽게 만든다.</li> + <li> + <p>우리가 어느 지역에서는 이것이 법의 적용을 받는다고 언급한 적이 있나요?</p> + </li> +</ul> + +<h2 id="어떤_종류의_장애를_본_적이_있습니까">어떤 종류의 장애를 본 적이 있습니까?</h2> + +<p>장애가 있는 사람들도 장애가 없는 사람들만큼이나 다양하고, 그만큰 그들의 장애유형도 다양합니다. 여기서 중요한 교훈은 자신이 컴퓨터와 웹을 어떻게 사용하는 지에 대해 생각하고 다른 사람들이 웹을 어떻게 사용하는 지에 대해 배우는 것이다.</p> + +<p>장애의 주요 유형은 웹 콘텐츠에 액세스 하는 데 사용하는 전문 도구와 함께 아래에 설명되어 있습니다.(흔히 보조공학기기또는 보조기술 이라고 알려진).</p> + +<div class="note"> +<p><strong>Note</strong>: 세계 보건 기구(WHO)의 장애 및 보건 현황 보고서에 따르면 전 세계 인구의 약 15%에 해당하는 십억명 이상의 사람들이 장애를 갖고 있으며 1억 1천만명에서 1억 9천만명의 성인들이 심각한 장애를 갖고 있다.</p> + +<p> </p> +</div> + +<h3 id="시각장애인">시각장애인</h3> + +<p>여기에는 전맹, 저시력 장애인 색각장애인등이 포함되며 이런 많은 사람들이 화면확대경(물리적 확대경 또는 소프트웨어 줌 기능 - 대부분의 브라우저와 운영 체제에는 최근 확대 / 축소 기능이 있음)과 디지털 글자를 큰소리로 읽어주는 소프트웨어인 화면낭독기를 사용한다.</p> + +<ul> + <li>일부는 <a class="external external-icon" href="http://www.freedomscientific.com/Products/Blindness/JAWS">JAWS</a> (Windows) 와 <a class="external external-icon" href="http://www.gwmicro.com/window-eyes/">Window Eyes</a> (Windows) 같은 상업적인 제품을 사용한다.</li> + <li>일부는 <a class="external external-icon" href="http://www.nvaccess.org/">NVDA</a> (Windows), <a class="external external-icon" href="http://www.chromevox.com/">ChromeVox</a> (Chrome, Windows and Mac OS X), 와 <a class="external external-icon" href="https://wiki.gnome.org/Projects/Orca">Orca</a> (Linux) 같은 무료 소프트웨어를 사용하기도 한다.</li> + <li>일부는 <a class="external external-icon" href="http://www.apple.com/accessibility/osx/voiceover/">VoiceOver</a> (Mac OS X and iOS), <a class="external external-icon" href="https://support.microsoft.com/en-us/help/22798/windows-10-narrator-get-started">Narrator</a> (Microsoft Windows), <a class="external external-icon" href="http://www.chromevox.com/">ChromeVox</a> (on Chrome OS), <a class="external external-icon" href="https://play.google.com/store/apps/details?id=com.google.android.marvin.talkback">TalkBack</a> (Android)과 같은 OS에 장착된 소프트 웨어를 사용하기도 한다.</li> +</ul> + +<p> </p> + +<p>스크린 리더들과 친숙해 지는 것은 좋은 생각이다; 당신은 또한 스크린 리더를 설치하고 그것을 가지고 노는 것이 어떻게 작동하는 지에 대한 아이디어를 얻기 위해서 필요하다. 사용에 대한 자세한 내용은 크로스 브라우저 테스트 화면 판독기 가이드( <a href="https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Accessibility#Screenreaders">cross browser testing screen readers guide</a>)를 참조하십시오. 아래의 비디오는 또한 경험이 어떠한지에 대한 간단한 예를 제공한다.</p> + +<p>{{EmbedYouTube("IK97XMibEws")}}</p> + +<p> </p> + +<p>In terms of statistics, the World Health Organization estimates that "285 million people are estimated to be visually impaired worldwide: 39 million are blind and 246 have low vision." (see <a href="http://www.who.int/mediacentre/factsheets/fs282/en/">Visual impairment and blindness</a>). That's a large and significant population of users to just miss out on because your site isn't coded properly — almost the same size as the population of the United States of America.</p> + +<h3 id="People_with_hearing_impairments">People with hearing impairments</h3> + +<p>Otherwise known as people with auditory impairments, or deaf people, this group of people have either low hearing levels or no hearing at all. Hearing-impaired people do use ATs (see <a href="https://www.nidcd.nih.gov/health/assistive-devices-people-hearing-voice-speech-or-language-disorders">Assistive Devices for People with Hearing, Voice, Speech, or Language Disorders</a>), but there are not really special ATs specific for computer/web use.</p> + +<p>There are, however, specific techniques to bear in mind for providing text alternatives to audio content that they can read, from simple text transcripts, to text tracks (i.e. captions) that can be displayed along with video. An article later on will discuss these.</p> + +<p>Hearing-impaired people also represent a significant userbase — "360 million people worldwide have disabling hearing loss", says the World Health Organization's <a href="http://www.who.int/mediacentre/factsheets/fs300/en/">Deafness and hearing loss</a> fact sheet.</p> + +<h3 id="People_with_mobility_impairments">People with mobility impairments</h3> + +<p>These people have disabilities concerning movement, which might involve purely physical issues (such as loss of limb or paralysis), or neurological/genetic disorders that lead to weakness or loss of control in limbs. Some people might have difficulty making the exact hand movements required to use a mouse, while others might be more severely affected, perhaps being significantly paralysed to the point where they need to use a <a href="http://pattersonmedical.com/app.aspx?cmd=getProductDetail&key=070_921118261">head pointer</a> to interact with computers.</p> + +<p>This kind of disability can also be a result of old age, rather than any specific trauma or condition, and it could also result from hardware limitations — some users might not have a mouse.</p> + +<p>The way this usually affects web development work is the requirement that controls be accessible by the keyboard — we'll discuss keyboard accessibility in later articles in the module, but it is a good idea to try out some websites using just the keyboard to see how you get on. Can you use the tab key to move between the different controls of a web form, for example? You can find more details about keyboard controls in our <a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Accessibility#Using_native_keyboard_accessibility">Cross browser testing Using native keyboard accessibility</a> section.</p> + +<p>In terms of statistics, a significant number of people have mobility impairments. The U.S. Centers for Disease Control and Prevention <a href="http://www.cdc.gov/nchs/fastats/disability.htm">Disability and Functioning (Noninstitutionalized Adults 18 Years and Over)</a> reports the USA "Percent of adults with any physical functioning difficulty: 15.1%".</p> + +<h3 id="People_with_cognitive_impairments">People with cognitive impairments</h3> + +<p>Probably the widest range of disabilities can be seen in this last category — cognitive impairment can broadly refer to disabilities from mental illnesses to learning difficulties, difficulties in comprehension and concentration like <a href="https://www.nimh.nih.gov/health/topics/attention-deficit-hyperactivity-disorder-adhd/index.shtml">ADHD (attention deficit hyperactivity disorder)</a>, to people on the <a href="https://www.nimh.nih.gov/health/topics/autism-spectrum-disorders-asd/index.shtml">autistic spectrum</a>, to people with <a href="https://www.nimh.nih.gov/health/topics/schizophrenia/index.shtml">schizophrenia</a>, and many other types of disorder besides. Such disabilities can affect many parts of everyday life, due to problems with memory, problem solving, comprehension, attention, etc.</p> + +<p>The most common ways that such disabilities might affect website usage is difficulty in understanding how to complete a task, remembering how to do something that was previously accomplished, or increased frustration at confusing workflows or inconsistent layouts/navigation/other page features.</p> + +<p>Unlike other web accessibility issues, it is impossible to prescribe quick fixes to many web accessibility issues arising from cognitive disabilities; the best chance you've got is to design your websites to be as logical, consistent, and usable as possible, so for example making sure that:</p> + +<ul> + <li>pages are consistent — navigation, header, footer, and main content are always in the same places.</li> + <li>tools are well-designed and easy to use.</li> + <li>multi-stage processes are broken down into logical steps, with regular reminders of how far through the process you are, and how long you've got left to complete the process, if appropriate.</li> + <li>workflows are logical, simple, and require as few interactions as possible to complete. For example, registering and signing in to a website is often unneccessarily complex.</li> + <li>pages are not overly long or dense in terms of the amount of information presented at once.</li> + <li>the language used in your pages is as plain and easy to follow as possible, and not full of unneccessary jargon and slang.</li> + <li>important points and content are highlighted in some way.</li> + <li>user errors are clearly highlighted, with help messages to suggest solutions.</li> +</ul> + +<p>These are not "accessibility techniques" as such — they are good design practices. They will benefit everyone using your sites and should be a standard part of your work.</p> + +<p>In terms of statistics, again the numbers are significant. Cornell University's <a href="http://www.disabilitystatistics.org/StatusReports/2014-PDF/2014-StatusReport_US.pdf">2014 Disability Status Report</a> (PDF, 511KB) indicates that in 2014, 4.5% of people in the USA aged 21–64 had some form of cognitive disability.</p> + +<div class="note"> +<p><strong>Note</strong>: WebAIM's <a href="http://webaim.org/articles/cognitive/">Cognitive</a> page provides a useful expansion of these ideas, and is certainly worth reading.</p> +</div> + +<h2 id="Implementing_accessibility_into_your_project">Implementing accessibility into your project</h2> + +<p>A common accessibility myth is that accessibility is an expensive "added extra" to implement on a project. This myth actually <em>can</em> be true if either:</p> + +<ul> + <li>You are trying to "retrofit" accessibility onto an existing website that has significant accessiblity issues.</li> + <li>You have only started to consider accessibility and uncovered related issues in the late stages of a project.</li> +</ul> + +<p>If however you consider accessibility from the start of a project, the cost of making most content accessible should be fairly minimal.</p> + +<p>When planning your project, factor accessibility testing into your testing regime, just like testing for any other important target audience segment (e.g. target desktop or mobile browsers). Test early and often, ideally running automated tests to pick up on programmatically detectable missing features (such as missing image <a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Accessibility#Text_alternatives">alternative text</a> or bad link text — see <a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Accessibility#Element_relationships_and_context">Element relationships and context</a>), and doing some testing with disabled user groups to see how well more complex site features work for them. For example:</p> + +<ul> + <li>Is my date picker widget usable by people using screen readers?</li> + <li>If content updates dynamically, do visually impaired people know about it?</li> + <li>Are my UI buttons accessible using the keyboard and on touch interfaces?</li> +</ul> + +<p>You can and should keep a note of potential problem areas in your content that will need work to make it accessible, make sure it is tested thoroughly, and think about solutions/alternatives. Text content (as you'll see in the next article) is easy, but what about your multimedia content, and your whizzy 3D graphics? You should look at your project budget and realistically think about what solutions you have available to make such content accessible? You could pay to have all your multimedia content transcribed, which can be expensive, but can be done.</p> + +<p>Also, be realistic. "100% accessibility" is an unobtainable ideal — you will always come across some kind of edge case that results in a certain user finding certain content difficult to use — but you should do as much as you can. If you are planning to include a whizzy 3D pie chart graphic made using WebGL, you might want to include a data table as an accessible alternative representation of the data. Or, you might want to just include the table and get rid of the 3D pie chart — the table is accessible by everyone, quicker to code, less CPU-intensive, and easier to maintain.</p> + +<p>On the other hand, if you are working on a gallery website showing interesting 3D art, it would be unreasonable to expect every piece of art to be perfectly accessible to visually impaired people, given that it is an entirely visual medium.</p> + +<p>To show that you care and have thought about accessibility, publish an accessibility statement on your site that details what your policy is toward accessibility, and what steps you have taken toward making the site accessible. If someone does complain that your site has an accessibility problem, start a dialog with them, be empathic, and take reasonable steps to try to fix the problem.</p> + +<div class="note"> +<p><strong>Note</strong>: Our <a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Accessibility">Handling common accessibility problems article</a> covers accessibility specifics that should be tested in more detail.</p> +</div> + +<p>To summarize:</p> + +<ul> + <li>Consider accessibility from the start of a project, and test early and often. Just like any other bug, an accessibility problem becomes more expensive to fix the later it is discovered.</li> + <li>Bear in mind that a lot of accessibility best practices benefit everyone, not just users with disabilities. For example, lean semantic markup is not only good for screen readers, it is also fast to load and performant, so better for everyone, especially those on mobile devices, and/or slow conections.</li> + <li>Publish an accessibility statement on your site and engage with people having problems.</li> +</ul> + +<h2 id="Accessibility_guidelines_and_the_law">Accessibility guidelines and the law</h2> + +<p>There are numerous checklists and sets of guidelines available for basing accessibility tests on, which might seem overwhelming at first glance. Our advice is to familiarize yourself with the basic areas in which you need to take care, as well as understanding the high level structures of the guidelines that are most relevant to you.</p> + +<ul> + <li>For a start, the W3C has published a large and very detailed document that includes very precise, technology-agnostic criteria for accessibility conformance. These are called the <a href="https://www.w3.org/WAI/intro/wcag.php">Web Content Accessibility Guidelines</a> (WCAG), and they are not a short read by any means. The criteria are split up into four main categories, which specify how implementations can be made perceivable, operable, understandable, and robust. The best place to get a light introduction and start learning is <a href="https://www.w3.org/WAI/WCAG20/glance/Overview.html">WCAG at a Glance</a>. There is no need to learn WCAG off by heart — be aware of the major areas of concern, and use a variety of techniques and tools to highlight any areas that don't conform to the WCAG criteria (see below for more).</li> + <li>Your country may also have specific legislation governing the need for websites serving their population to be accessible — for example <a href="http://www.section508.gov/content/learn">Section 508 of the Rehabilitation Act</a> in the US, <a href="https://www.einfach-fuer-alle.de/artikel/bitv_english/">Federal Ordinance on Barrier-Free Information Technology</a> in Germany, the <a href="http://www.legislation.gov.uk/ukpga/2010/15/contents">Equality Act</a> in the UK, <a href="http://www.agid.gov.it/agenda-digitale/pubblica-amministrazione/accessibilita">Accessibilità</a> in Italy, the <a href="https://www.humanrights.gov.au/world-wide-web-access-disability-discrimination-act-advisory-notes-ver-41-2014">Disability Discrimination Act</a> in Australia, etc.</li> +</ul> + +<p>So while the WCAG is a set of guidelines, your country will probably have laws governing web accessibility, or at least the accessibility of services available to the public (which could include websites, television, physical spaces, etc.) It is a good idea to find out what your laws are. If you make no effort to check that your content is accessible, you could possibly get in trouble with the law if people with diabilities complain about it.</p> + +<p>This sounds serious, but really you just need to consider accessibility as a main priority of your web development practices, as outlined above. If in doubt, get advice from a qualified lawyer. We're not going to offer any more advice than this, because we're not lawyers.</p> + +<h2 id="Accessibility_APIs">Accessibility APIs</h2> + +<p>Web browsers make use of special <strong>accessibility APIs</strong> (provided by the underlying operating system) that expose information useful for assistive technologies (ATs) — ATs mostly tend to make use of semantic information, so this information doesn't include things like styling information, or JavaScript. This information is structured in a tree of information called the <strong>accessibility tree</strong>.</p> + +<p>Different operating systems have different accessibility APIs available :</p> + +<ul> + <li>Windows: MSAA/IAccessible, UIAExpress, IAccessible2</li> + <li>Mac OS X: NSAccessibility</li> + <li>Linux: AT-SPI</li> + <li>Android: Accessibility framework</li> + <li>iOS: UIAccessibility</li> +</ul> + +<p>Where the native semantic information provided by the HTML elements in your web apps falls down, you can supplement it with features from the <a href="https://www.w3.org/TR/wai-aria/">WAI-ARIA specification</a>, which add semantic information to the accessibility tree to improve accessibility. You can learn a lot more about WAI-ARIA in our <a href="/en-US/docs/Learn/Accessibility/WAI-ARIA_basics">WAI-ARIA basics</a> article.</p> + +<h2 id="Summary">Summary</h2> + +<p>This article should have given you a useful high level overview of accessibility, shown you why it's important, and looked at how you can fit it into your workflow. You should now also have a thirst to learn about the implementation details that can make sites accessible, and we'll start on that in the next section, looking at why HTML is a good basis for accessibility.</p> + +<p>{{NextMenu("Learn/Accessibility/HTML", "Learn/Accessibility")}}</p> + +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Accessibility/What_is_accessibility">What is accessibility?</a></li> + <li><a href="/en-US/docs/Learn/Accessibility/HTML">HTML: A good basis for accessibility</a></li> + <li><a href="/en-US/docs/Learn/Accessibility/CSS_and_JavaScript">CSS and JavaScript accessibility best practices</a></li> + <li><a href="/en-US/docs/Learn/Accessibility/WAI-ARIA_basics">WAI-ARIA basics</a></li> + <li><a href="/en-US/docs/Learn/Accessibility/Multimedia">Accessible multimedia</a></li> + <li><a href="/en-US/docs/Learn/Accessibility/Mobile">Mobile accessibility</a></li> + <li><a href="/en-US/docs/Learn/Accessibility/Accessibility_troubleshooting">Accessibility troubleshooting</a></li> +</ul> diff --git a/files/ko/learn/접근성/모바일/index.html b/files/ko/learn/접근성/모바일/index.html new file mode 100644 index 0000000000..a64c0eaa88 --- /dev/null +++ b/files/ko/learn/접근성/모바일/index.html @@ -0,0 +1,315 @@ +--- +title: 모바일 접근성 +slug: Learn/접근성/모바일 +translation_of: Learn/Accessibility/Mobile +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/Accessibility/Multimedia","Learn/Accessibility/Accessibility_troubleshooting", "Learn/Accessibility")}}</div> + +<p class="summary">모바일 기기에서 웹 접근이 매우 자주 발생하고 iOS와 안드로이드와 같은 유명 플랫폼들은 전문적인 접근성 점검도구들이 있기 때문에 웹콘텐츠의 접근성을 고려하는 것이 더욱 중요하다. 여기서는 모바일환경을 중심으로 접근성 고려사항을 살펴본다.</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">사전지식:</th> + <td> + <p>기본적인 컴퓨터 사용능력, HTML, CSS, JavaScript에 대한 기본적인 이해, 그리고 <a href="/en-US/docs/Learn/Accessibility">이전 내용들에 대한 이해</a>.</p> + </td> + </tr> + <tr> + <th scope="row">목표:</th> + <td> + <p>모바일 기기의 접근성에 어떤 문제가 있는지, 그리고 이를 극복하는 방법을 이해한다.</p> + </td> + </tr> + </tbody> +</table> + +<h2 id="모바일_장치에서의_접근성">모바일 장치에서의 접근성</h2> + +<p>접근성 상태(일반적으로 웹 표준에 대한 지원)는 최근의 모바일 장치에서 좋다. 모바일 기기가 데스크톱 브라우저에 전혀 다른 웹 기술을 실행하면서 개발자들이 브라우저 코웃음을 치며 완전히 별개의 사이트에 서비스를 제공하도록 강요하던 시대는 이미 오래 전에 지났다(아직도 상당수의 회사가 모바일 장치의 사용을 감지하여 별도의 모바일 도메인을 서비스하고 있다).</p> + + + +<p>The state of accessibility — and support for web standards in general — is good in modern mobile devices. Long gone are the days when mobile devices ran completely different web technologies to desktop browsers, forcing developers to use browser sniffing and serve them completely separate sites (although quite a few companies still detect usage of mobile devices and serve them a separate mobile domain).</p> + +<p>These days, mobile devices can usually handle fully-featured websites, and the main platforms even have screenreaders built in to enable visually impaired users to use them successfully. Modern mobile browsers tend to have good support for <a href="https://developer.mozilla.org/en-US/docs/Learn/Accessibility/WAI-ARIA_basics">WAI-ARIA</a>, too.</p> + +<p>To make a website accessible and usable on mobile, you just need to follow general good web design and accessibility best practices.</p> + +<p>There are some exceptions that need special consideration for mobile; the main ones are:</p> + +<ul> + <li>Control mechanisms — Make sure interface controls such as buttons are accessible on mobiles (i.e., mainly touchscreen), as well as desktops/laptops (mainly mouse/keyboard).</li> + <li>User input — Make user input requirements as painless as possible on mobile (e.g., in forms, keep typing to a minimum).</li> + <li>Responsive design — Make sure layouts work on mobile, conserve image download sizes, and think about the provision of images for high-resolution screens.</li> +</ul> + +<h2 id="Summary_of_screenreader_testing_on_Android_and_iOS">Summary of screenreader testing on Android and iOS</h2> + +<p>The most common mobile platforms have fully functional screen readers. These function in much the same way as desktop screenreaders, except they are largely operated using touch gestures rather than key combinations.</p> + +<p>Let's look at the main two: TalkBack on Android and VoiceOver on iOS.</p> + +<h3 id="Android_TalkBack">Android TalkBack</h3> + +<p>The TalkBack screen reader is built into the Android operating system.</p> + +<p>To turn it on, look up what phone model and Android version you have, and then look up where the TalkBack menu is. It tends to differ widely between Android versions and even between different phone models. Some phone manufacturers (e.g. Samsung) don't even have TalkBack in newer phones, and instead opted for their own screen reader.</p> + +<p>When you've found the TalkBack menu, press the slider switch to turn TalkBack on. Follow any additional on-screen prompts that you are presented with.</p> + +<p>When TalkBack is turned on, your Android device's basic controls will be a bit different. For example:</p> + +<ol> + <li>Single-tapping an app will select it, and the device will read out what the app is.</li> + <li>Swiping left and right will move between apps, or buttons/controls if you are in a control bar. The device will read out each option.</li> + <li>Double-tapping anywhere will open the app/select the option.</li> + <li>You can also "explore by touch" — hold your finger down on the screen and drag it around, and your device will read out the different apps/items you move across.</li> +</ol> + +<p>If you want to turn TalkBack off:</p> + +<ol> + <li>Navigate back to the TalkBack menu screen (using the different gestures that are currently enabled.)</li> + <li>Navigate to the slider switch and activate it to turn it off.</li> +</ol> + +<div class="blockIndicator note"> +<p><strong>Note:</strong> You can get to your home screen at any time by swiping up and left in a smooth motion. If you have more than one home screen, you can move between them by swiping two fingers left and right.</p> +</div> + +<p>For a more complete list of TalkBack gestures, see <a href="https://support.google.com/accessibility/android/answer/6151827">Use TalkBack gestures</a>.</p> + +<h4 id="Unlocking_the_phone">Unlocking the phone</h4> + +<p>When TalkBack is turned on, unlocking the phone is a bit different.</p> + +<p>You can do a two-finger swipe up from the bottom of the lock screen. If you've set a passcode or pattern for unlocking your device, you will then be taken to the relevant entry screen to enter it.</p> + +<p>You can also explore by touch to find the <em>Unlock</em> button at the bottom middle of the screen, and then double-tap.</p> + +<h4 id="Global_and_local_menus">Global and local menus</h4> + +<p>TalkBack allows you to access global and local context menus, wherever you have navigated to on the device. The former provides global options relating to the device as a whole, and the latter provides options relating just to the current app/screen you are in.</p> + +<p>To get to these menus:</p> + +<ol> + <li>Access the global menu by quickly swiping down, and then right.</li> + <li>Access the local menu by quickly swiping up, and then right.</li> + <li>Swipe left and right to cycle between the different options.</li> + <li>Once you've selected the option you want, double-click to choose that option.</li> +</ol> + +<p>For details on all the options available under the global and local context menus, see <a href="https://support.google.com/accessibility/android/answer/6007066">Use global and local context menus</a>.</p> + +<h4 id="Browsing_web_pages">Browsing web pages</h4> + +<p>You can use the local context menu while in a web browser to find options to navigate web pages using just the headings, form controls, or links, or navigate line by line, etc.</p> + +<p>For example, with TalkBack turned on:</p> + +<ol> + <li>Open your web browser.</li> + <li>Activate the URL bar.</li> + <li>Enter a web page that has a bunch of headings on it, such as the front page of bbc.co.uk. To enter the text of the URL: + <ul> + <li>Select the URL bar by swiping left/right till you get to it, and then double-tapping.</li> + <li>Hold your finger down on the virtual keyboard until you get the character you want, and then release your finger to type it. Repeat for each character.</li> + <li>Once you've finished, find the Enter key and press it.</li> + </ul> + </li> + <li>Swipe left and right to move between different items on the page.</li> + <li>Swipe up and right with a smooth motion to enter the local content menu.</li> + <li>Swipe right until you find the "Headings and Landmarks" option.</li> + <li>Double-tap to select it. Now you'll be able to swipe left and right to move between headings and ARIA landmarks.</li> + <li>To go back to the default mode, enter the local context menu again by swiping up and right, select "Default", and then double-tap to activate.</li> +</ol> + +<p><strong>Note:</strong> See <a href="https://support.google.com/accessibility/android/answer/6283677?hl=en&ref_topic=3529932">Get started on Android with TalkBack</a> for more complete documentation.</p> + +<h3 id="iOS_VoiceOver">iOS VoiceOver</h3> + +<p>A mobile version of VoiceOver is built into the iOS operating system.</p> + +<p>To turn it on, go to Your <em>Settings</em> app and select<em> Accessibility > VoiceOver</em>. Press the <em>VoiceOver</em> slider to enable it (you'll also see a number of other options related to VoiceOver on this page).</p> + +<div class="blockIndicator note"> +<p><strong>Note</strong>: Some older iOS devices have the VoiceOver menu at <em>Settings app</em> > <em>General</em> > <em>Accessibility</em> > <em>VoiceOver</em>.</p> +</div> + +<p>Once VoiceOver is enabled, iOS's basic control gestures will be a bit different:</p> + +<ol> + <li>A single tap will cause the item you tap on to be selected; your device will speak the item you've tapped on.</li> + <li>You can also navigate the items on the screen by swiping left and right to move between them, or by sliding your finger around on the screen to move between different items (when you find the item you want, you can remove your finger to select it).</li> + <li>To activate the selected item (e.g., open a selected app), double-tap anywhere on the screen.</li> + <li>Swipe with three fingers to scroll through a page.</li> + <li>Tap with two fingers to perform a context-relevant action — for example, taking a photo while in the camera app.</li> +</ol> + +<p>To turn it off again, navigate back to <em>Settings > General > Accessibility > VoiceOver</em> using the above gestures, and toggle the <em>VoiceOver</em> slider back to off.</p> + +<h4 id="Unlock_phone">Unlock phone</h4> + +<p>To unlock the phone, you need to press the home button (or swipe) as normal. If you have a passcode set, you can select each number by swiping/sliding (as explained above) and then double-tapping to enter each number when you've found the right one.</p> + +<h4 id="Using_the_Rotor">Using the Rotor</h4> + +<p>When VoiceOver is turned on, you have a navigation feature called the Rotor available to you, which allows you to quickly choose from a number of common useful options. To use it:</p> + +<ol> + <li>Twist two fingers around on the screen like you are turning a dial. Each option will be read aloud as you twist further around. You can go back and forth to cycle through the options.</li> + <li>Once you've found the option you want: + <ul> + <li>Release your fingers to select it.</li> + <li>If it is an option you can iterate the value of (such as Volume or Speaking Rate), you can do a swipe up or down to increase or decrease the value of the selected item.</li> + </ul> + </li> +</ol> + +<p>The options available under the Rotor are context-sensitive — they will differ depending on what app or view you are in (see below for an example).</p> + +<h4 id="Browsing_web_pages_2">Browsing web pages</h4> + +<p>Let's have a go at web browsing with VoiceOver:</p> + +<ol> + <li>Open your web browser.</li> + <li>Activate the URL bar.</li> + <li>Enter a web page that has a bunch of headings on it, such as the front page of bbc.co.uk. To enter the text of the URL: + <ul> + <li>Select the URL bar by swiping left/right until you get to it, and then double-tapping.</li> + <li>For each character, hold your finger down on the virtual keyboard until you get the character you want, and then release your finger to select it. Double-tap to type it.</li> + <li>Once you've finished, find the Enter key and press it.</li> + </ul> + </li> + <li>Swipe left and right to move between items on the page. You can double-tap an item to select it (e.g., follow a link).</li> + <li>By default, the selected Rotor option will be Speaking Rate; you can currently swipe up and down to increase or decrease the speaking rate.</li> + <li>Now turn two fingers around the screen like a dial to show the rotor and move between its options. Here are a few examples of the options available: + <ul> + <li><em>Speaking Rate</em>: Change the speaking rate.</li> + <li><em>Containers</em>: Move between different semantic containers on the page.</li> + <li><em>Headings</em>: Move between headings on the page.</li> + <li><em>Links</em>: Move between links on the page.</li> + <li><em>Form Controls</em>: Move between form controls on the page.</li> + <li><em>Language</em>: Move between different translations, if they are available.</li> + </ul> + </li> + <li>Select <em>Headings</em>. Now you'll be able to swipe up and down to move between headings on the page.</li> +</ol> + +<p><strong>Note:</strong> For a more complete reference covering the VoiceOver gestures available and other hints on accessibility testing on iOS, see <a href="https://developer.apple.com/library/content/technotes/TestingAccessibilityOfiOSApps/TestAccessibilityonYourDevicewithVoiceOver/TestAccessibilityonYourDevicewithVoiceOver.html#//apple_ref/doc/uid/TP40012619-CH3">Test Accessibility on Your Device with VoiceOver</a>.</p> + +<h2 id="Control_mechanisms">Control mechanisms</h2> + +<p>In our CSS and JavaScript accessibility article, we looked at the idea of events that are specific to a certain type of control mechanism (see <a href="https://developer.mozilla.org/en-US/docs/Learn/Accessibility/CSS_and_JavaScript#mouse-specific_events">Mouse-specific events</a>). To recap, these cause accessibility issues because other control mechanisms can't activate the associated functionality.</p> + +<p>As an example, the <a href="https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onclick">click</a> event is good in terms of accessibility — an associated event handler can be invoked by clicking the element the handler is set on, tabbing to it and pressing Enter/Return, or tapping it on a touchscreen device. Try our <a href="https://github.com/mdn/learning-area/blob/master/accessibility/mobile/simple-button-example.html">simple-button-example.html</a> example (<a href="http://mdn.github.io/learning-area/accessibility/mobile/simple-button-example.html">see it running live</a>) to see what we mean.</p> + +<p>Alternatively, mouse-specific events such as <a href="https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onmousedown">mousedown</a> and <a href="https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onmouseup">mouseup</a> create problems — their event handlers cannot be invoked using non-mouse controls.</p> + +<p>If you try to control our <a href="https://github.com/mdn/learning-area/blob/master/accessibility/mobile/simple-box-drag.html">simple-box-drag.html</a> (<a href="http://mdn.github.io/learning-area/accessibility/mobile/simple-box-drag.html">see example live</a>) example with a keyboard or touch, you'll see the problem. This occurs because we are using code such as the following:</p> + +<pre>div.onmousedown = function() { + initialBoxX = div.offsetLeft; + initialBoxY = div.offsetTop; + movePanel(); +} + +document.onmouseup = stopMove;</pre> + +<p>To enable other forms of control, you need to use different, yet equivalent events — for example, touch events work on touchscreen devices:</p> + +<pre>div.ontouchstart = function(e) { + initialBoxX = div.offsetLeft; + initialBoxY = div.offsetTop; + positionHandler(e); + movePanel(); +} + +panel.ontouchend = stopMove;</pre> + +<p>We've provided a simple example that shows how to use the mouse and touch events together — see <a href="https://github.com/mdn/learning-area/blob/master/accessibility/mobile/multi-control-box-drag.html">multi-control-box-drag.html</a> (<a href="http://mdn.github.io/learning-area/accessibility/mobile/multi-control-box-drag.html">see the example live</a> also).</p> + +<div class="blockIndicator note"> +<p><strong>Note:</strong> You can also see fully functional examples showing how to implement different control mechanisms at <a href="https://developer.mozilla.org/en-US/docs/Games/Techniques/Control_mechanisms">Implementing game control mechanisms</a>.</p> +</div> + +<h2 id="Responsive_design">Responsive design</h2> + +<p><a href="https://developer.mozilla.org/en-US/docs/Web/Apps/Progressive/Responsive">Responsive design</a> is the practice of making your layouts and other features of your apps dynamically change depending on factors such as screen size and resolution, so they are usable and accessible to users of different device types.</p> + +<p>In particular, the most common problems that need to be addressed for mobile are:</p> + +<ul> + <li>Suitability of layouts for mobile devices. A multi-column layout won't work as well on a narrow screen, for example, and the text size may need to be increased so it is legible. Such issues can be solved by creating a responsive layout using technologies such as <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries">media queries</a>, <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Mobile/Viewport_meta_tag">viewport</a>, and <a href="https://developer.mozilla.org/en-US/docs/Learn/CSS/CSS_layout/Flexbox">flexbox</a>.</li> + <li>Conserving image sizes downloaded. In general, small screen devices won't need images that are as large as their desktop counterparts, and they are more likely to be on slow network connections. Therefore, it is wise to serve smaller images to narrow screen devices as appropriate. You can handle this using <a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images">responsive image techniques</a>.</li> + <li>Thinking about high resolutions. Many mobile devices have high-resolution screens, and therefore need higher-resolution images so that the display can continue to look crisp and sharp. Again, you can serve images as appropriate using responsive image techniques. In addition, many image requirements can be fulfilled using the SVG vector images format, which is well-supported across browsers today. SVG has a small file size and will stay sharp regardless of whatever size is being displayed (see <a href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Adding_vector_graphics_to_the_Web">Adding vector graphics to the web</a> for more details).</li> +</ul> + +<p><strong>Note:</strong> We won't provide a full discussion of responsive design techniques here, as they are covered in other places around MDN (see above links).</p> + +<h3 id="Specific_mobile_considerations">Specific mobile considerations</h3> + +<p>There are other important issues to consider when making sites more accessible on mobile. We have listed a couple here, but we will add more when we think of them.</p> + +<h4 id="Not_disabling_zoom">Not disabling zoom</h4> + +<p>Using <a href="https://developer.mozilla.org/en-US/docs/Mozilla/Mobile/Viewport_meta_tag">viewport</a>, it is possible to disable zoom. Always ensure resizing is enabled, and set the width to the device's width in the {{htmlelement("head")}}:</p> + +<pre class="brush: html"><code><meta name="viewport" content="width=device-width; user-scalable=yes"></code></pre> + +<p>You should never set <code>user-scalable=no</code> if at all possible — many people rely on zoom to be able to see the content of your website, so taking this functionality away is a really bad idea. There are certain situations where zooming might break the UI; in such cases, if you feel that you absolutely need to disable zoom, you should provide some other kind of equivalent, such as a control for increasing the text size in a way that doesn't break your UI.</p> + +<h4 id="Keeping_menus_accessible">Keeping menus accessible</h4> + +<p>Because the screen is so much narrower on mobile devices, it is very common to use media queries and other technologies to make the navigation menu shrink down to a tiny icon at the top of the display — which can be pressed to reveal the menu only if it's needed — when the site is viewed on mobile. This is commonly represented by a "three horizontal lines" icon, and the design pattern is consequently known as a "hamburger menu".</p> + +<p>When implementing such a menu, you need to make sure that the control to reveal it is accessible by appropriate control mechanisms (normally touch for mobile), as discussed in {{anch("Control mechanisms")}} above, and that the rest of the page is moved out of the way or hidden in some way while the menu is being accessed, to avoid confusion with navigating it.</p> + +<p>Click here for a <a href="http://fritz-weisshart.de/meg_men/">good hamburger menu example</a>.</p> + +<h2 id="User_input">User input</h2> + +<p>On mobile devices, inputting data tends to be more annoying for users than the equivalent experience on desktop computers. It is more convenient to type text into form inputs using a desktop or laptop keyboard than a touchscreen virtual keyboard or a tiny mobile physical keyboard.</p> + +<p>For this reason, it is worth trying to minimize the amount of typing needed. As an example, instead of getting users to fill out their job title each time using a regular text input, you could instead offer a {{htmlelement("select")}} menu containing the most common options (which also helps with consistency in data entry), and offer an "Other" option that displays a text field to type any outliers into. You can see a simple example of this idea in action in <a href="https://github.com/mdn/learning-area/blob/master/accessibility/mobile/common-job-types.html">common-job-types.html</a> (see the <a href="http://mdn.github.io/learning-area/accessibility/mobile/common-job-types.html">common jobs example live</a>).</p> + +<p>It is also worth considering the use of HTML5 form input types such as the date on mobile platforms as they handle them well — both Android and iOS, for example, display usable widgets that fit well with the device experience. See <a href="https://github.com/mdn/learning-area/blob/master/accessibility/mobile/html5-form-examples.html">html5-form-examples.html</a> for some examples (see the <a href="http://mdn.github.io/learning-area/accessibility/mobile/html5-form-examples.html">HTML5 form examples live</a>) — try loading these and manipulating them on mobile devices. For example:</p> + +<ul> + <li>Types <code>number</code>, <code>tel</code>, and <code>email</code> display suitable virtual keyboards for entering numbers/telephone numbers.</li> + <li>Types <code>time</code> and <code>date</code> display suitable pickers for selecting times and dates.</li> +</ul> + +<p>If you want to provide a different solution for desktops, you could always serve different markup to your mobile devices using feature detection. See <a href="http://diveinto.html5doctor.com/detect.html#input-types">input types</a> for raw information on detecting different input types, and also check out our <a href="https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Feature_detection">feature detection article</a> for much more information.</p> + +<h2 id="Summary">Summary</h2> + +<p>In this article, we have provided you with some details about common mobile accessibility-specific issues and how to overcome them. We also took you through the usage of the most common screenreaders to aid you in accessibility testing.</p> + +<h2 id="See_also">See also</h2> + +<ul> + <li><a href="https://www.smashingmagazine.com/guidelines-for-mobile-web-development/">Guidelines For Mobile Web Development</a> — A list of articles in <em>Smashing Magazine</em> covering different techniques for mobile web design.</li> + <li><a href="http://www.creativebloq.com/javascript/make-your-site-work-touch-devices-51411644">Make your site work on touch devices</a> — Useful article about using touch events to get interactions working on mobile devices.</li> +</ul> + +<div>{{PreviousMenuNext("Learn/Accessibility/Multimedia","Learn/Accessibility/Accessibility_troubleshooting", "Learn/Accessibility")}}</div> + +<div> +<h2 id="In_this_module">In this module</h2> + +<ul> + <li><a href="/en-US/docs/Learn/Accessibility/What_is_accessibility">What is accessibility?</a></li> + <li><a href="/en-US/docs/Learn/Accessibility/HTML">HTML: A good basis for accessibility</a></li> + <li><a href="/en-US/docs/Learn/Accessibility/CSS_and_JavaScript">CSS and JavaScript accessibility best practices</a></li> + <li><a href="/en-US/docs/Learn/Accessibility/WAI-ARIA_basics">WAI-ARIA basics</a></li> + <li><a href="/en-US/docs/Learn/Accessibility/Multimedia">Accessible multimedia</a></li> + <li><a href="/en-US/docs/Learn/Accessibility/Mobile">Mobile accessibility</a></li> + <li><a href="/en-US/docs/Learn/Accessibility/Accessibility_troubleshooting">Accessibility troubleshooting</a></li> +</ul> +</div> |