Do you like Pinterest? I am sure that yes, and, it is likely that you would like to create a similar photo website. I made up my mind to write a series of tutorials about development of similar script. For a start – let’s decide what features will be included into the script. I think, that besides of good design and friendly interface, we have to add next things: ajaxy popup to display full-size photos, possibility to write comments, like functionality, upload form, a way to sort photos (depends on its size) automatically and maybe something else. In our first lesson I prepared html markup with styles of our script. Also, in order to sort photos (align them) – I am going to use ‘masonry’ jQuery plugin.
Now you can check our demonstration and download the sources:
Live Demo
[sociallocker]
download in package
[/sociallocker]
Step 1. HTML
As always, our first step is html markup. In the beginning – we have to include all the necessary styles and scripts in the head section:
01 | <!DOCTYPE html> |
02 | <html lang="en" > |
03 | <head> |
04 | <meta charset="utf-8" /> |
05 | <meta name="author" content="Script Tutorials" /> |
06 | <title>How to create Pinterest-like script - step 1 | Script Tutorials</title> |
07 | <!-- add styles --> |
08 | <link href="css/main.css" rel="stylesheet" type="text/css" /> |
09 | <!-- add scripts --> |
10 | <script src="js/jquery.min.js"></script> |
11 | <script src="js/jquery.masonry.min.js"></script> |
12 | <script src="js/script.js"></script> |
13 | </head> |
Now we can mark the main page structure. Schematically it looks like this:
01 | <body> |
02 | <!-- header panel --> |
03 | <div class="header_panel"> |
04 | <!-- logo --> |
05 | <a href="#" class="logo"></a> |
06 | <!-- search form --> |
07 | <form action="" method="get" class="search"> |
08 | ..... |
09 | </form> |
10 | <!-- navigation menu --> |
11 | <ul class="nav"> |
12 | ..... |
13 | </ul> |
14 | </div> |
15 | <!-- upload form --> |
16 | <a href="#x" class="overlay" id="add_form"></a> |
17 | <div class="popup"> |
18 | ..... |
19 | </div> |
20 | <!-- main container with pin elements --> |
21 | <div class="main_container"> |
22 | ..... |
23 | </div> |
24 | </body> |
There are three main elements: header, upload form and main container (for pin elements). The header consists of a logo, search form and navigation menu. Look at its html markup:
01 | <!-- header panel --> |
02 | <div class="header_panel"> |
03 | <!-- logo --> |
04 | <a href="#" class="logo"></a> |
05 | <!-- search form --> |
06 | <form action="" method="get" class="search"> |
07 | <input autocomplete="off" name="q" size="27" placeholder="Search" type="text" /> |
08 | <input name="search" type="submit" /> |
09 | </form> |
10 | <!-- navigation menu --> |
11 | <ul class="nav"> |
12 | <li><a href="#add_form" id="login_pop">Add +</a></li> |
13 | <li> |
14 | <a href="#">About<span></span></a> |
15 | <ul> |
16 | <li><a href="#">Help</a></li> |
17 | <li><a href="#">Pin It Button</a></li> |
18 | <li><a href="#" target="_blank">For Businesses</a></li> |
19 | <li class="div"><a href="#">Careers</a></li> |
20 | <li><a href="#">Team</a></li> |
21 | <li><a href="#">Blog</a></li> |
22 | <li class="div"><a href="#">Terms of Service</a></li> |
23 | <li><a href="#">Privacy Policy</a></li> |
24 | <li><a href="#">Copyright</a></li> |
25 | <li><a href="#">Trademark</a></li> |
26 | </ul> |
27 | </li> |
28 | <li> |
29 | <a href="#">Profile<span></span></a> |
30 | <ul> |
31 | <li><a href="#">Invite Friends</a></li> |
32 | <li><a href="#">Find Friends</a></li> |
33 | <li class="div"><a href="#">Boards</a></li> |
34 | <li><a href="#">Pins</a></li> |
35 | <li><a href="#">Likes</a></li> |
36 | <li class="div"><a href="#">Settings</a></li> |
37 | <li><a href="#">Logout</a></li> |
38 | </ul> |
39 | </li> |
40 | <li> |
41 | <a href="https://www.script-tutorials.com/pinterest-like-script-step-1/">Back to tutorial<span></span></a> |
42 | </li> |
43 | </ul> |
44 | </div> |
As you see – everything is easy here. The second main element is upload form, I’m going to use the power of CSS3 to make CSS-based popup:
01 | <!-- upload form --> |
02 | <a href="#x" class="overlay" id="add_form"></a> |
03 | <div class="popup"> |
04 | <div class="header"> |
05 | <a class="close" href="#close">x</a> |
06 | <h2>Upload a Pin</h2> |
07 | </div> |
08 | <form> |
09 | <input type="file" name="image_file" id="image_file" onchange="" /> |
10 | </form> |
11 | </div> |
You can find related CSS styles in the second step of our tutorial. Finally, it is important to review html markup of our photo units (or – pins):
01 | <div class="pin"> |
02 | <div class="holder"> |
03 | <div class="actions" pin_id="1"> |
04 | <a href="#" class="button">Repin</a> |
05 | <a href="#" class="button">Like</a> |
06 | <a href="#" class="button disabled comment_tr">Comment</a> |
07 | </div> |
08 | <a class="image ajax" href="#" title="Photo number 1" pin_id="1"> |
09 | <img alt="Photo number 1" src="photos/pic1.jpg"> |
10 | </a> |
11 | </div> |
12 | <p class="desc">Photo number 1 description</p> |
13 | <p class="info"> |
14 | <span>1 likes</span> |
15 | <span>1 repins</span> |
16 | </p> |
17 | <form class="comment" method="post" action=""> |
18 | <input type="hidden" name="id" value="1" /> |
19 | <textarea placeholder="Add a comment..." maxlength="1000"></textarea> |
20 | <button type="button" class="button">Comment</button> |
21 | </form> |
22 | </div> |
Every pin consists of a holder element (action buttons and thumbnail image), description, info row, and comments box.
Step 2. CSS
Now, I would like to give you CSS styles to stylize today’s result. First section is base styles:
css/main.css
01 | /* base styles */ |
02 | * { |
03 | margin: 0; |
04 | padding: 0; |
05 | } |
06 | html { |
07 | background-color: #F7F5F5; |
08 | font-size: 10px; |
09 | font-family: arial,sans-serif; |
10 | } |
11 | a { |
12 | color: #221919; |
13 | text-decoration: none; |
14 | } |
Then, we can stylize our header area:
001 | /* header elements */ |
002 | .header_panel { |
003 | background-color: #FAF7F7; |
004 | box-shadow: 0 1px #FFFFFF inset, 0 1px 3px rgba(34, 25, 25, 0.4); |
005 | height: 44px; |
006 | left: 0; |
007 | padding: 0 7px; |
008 | position: relative; |
009 | right: 0; |
010 | top: 0; |
011 | z-index: 1; |
012 | } |
013 | .logo { |
014 | background: url("../images/logo.png") repeat scroll 0 0 transparent; |
015 | display: block; |
016 | height: 30px; |
017 | left: 50%; |
018 | margin-left: -50px; |
019 | position: absolute; |
020 | top: 10px; |
021 | width: 100px; |
022 | } |
023 | .search { |
024 | float: left; |
025 | margin: 8px 0 0; |
026 | } |
027 | .search input[type=text] { |
028 | background-color: #FAF7F7; |
029 | border-color: #C2C0C0 #CCCACA #D1CFCF; |
030 | border-image: none; |
031 | border-style: solid; |
032 | border-width: 1px; |
033 | box-shadow: 0 1px #FFFFFF, 0 1px rgba(34, 25, 25, 0.05) inset; |
034 | color: #8C7E7E; |
035 | float: left; |
036 | font-size: 13px; |
037 | height: 16px; |
038 | padding: 5px; |
039 | width: 180px; |
040 | -webkit-transition: all .5s; |
041 | -moz-transition: all .5s; |
042 | -ms-transition: all .5s; |
043 | -o-transition: all .5s; |
044 | transition: all .5s; |
045 | } |
046 | .search input[type=text]:focus { |
047 | background-color: #FFFFFF; |
048 | box-shadow: 0 1px #FFFFFF, 0 1px rgba(34, 25, 25, 0.1) inset; |
049 | width: 250px; |
050 | } |
051 | .search input[type=submit] { |
052 | background: url("../images/search.gif") no-repeat scroll center center transparent; |
053 | border-color: #C2C0C0 #CCCACA #D1CFCF; |
054 | border-style: solid; |
055 | border-width: 1px; |
056 | box-shadow: 0 1px rgba(255, 255, 255, 0.9), 0 0 2px rgba(255, 255, 255, 0.75) inset; |
057 | color: transparent; |
058 | content: ""; |
059 | cursor: pointer; |
060 | float: left; |
061 | height: 28px; |
062 | margin-left: -1px; |
063 | min-height: 17px; |
064 | padding: 7px 7px 1px; |
065 | width: 30px; |
066 | } |
067 | /* navigation styles */ |
068 | .nav { |
069 | float: right; |
070 | position: relative; |
071 | } |
072 | .nav li { |
073 | display: inline; |
074 | font-size: 13px; |
075 | position: relative; |
076 | } |
077 | .nav > li > a { |
078 | color: #524D4D; |
079 | cursor: pointer; |
080 | display: inline-block; |
081 | font-weight: bold; |
082 | height: 29px; |
083 | padding: 15px 27px 0 14px; |
084 | position: relative; |
085 | text-decoration: none; |
086 | text-shadow: 0 1px #FFFFFF; |
087 | } |
088 | .nav > li > a span { |
089 | background: url("../images/down.png") no-repeat scroll center top transparent; |
090 | height: 6px; |
091 | position: absolute; |
092 | right: 14px; |
093 | top: 20px; |
094 | width: 7px; |
095 | } |
096 | .nav > li:hover > a { |
097 | background-color: #E1DFDF; |
098 | color: #221919; |
099 | text-decoration: none; |
100 | text-shadow: 0 1px rgba(255, 255, 255, 0.3); |
101 | } |
102 | .nav > li:active > a { |
103 | background-color: #CB2027; |
104 | color: #FFFFFF; |
105 | text-shadow: 0 -1px rgba(34, 25, 25, 0.3); |
106 | } |
107 | .nav li ul { |
108 | background-color: #FFFFFF; |
109 | border-top: 1px solid #CCCACA; |
110 | box-shadow: 0 2px 4px rgba(34, 25, 25, 0.5); |
111 | display: none; |
112 | left: 0; |
113 | position: absolute; |
114 | top: 28px; |
115 | width: 140px; |
116 | z-index: 1; |
117 | } |
118 | .nav li:hover ul { |
119 | display: block; |
120 | } |
121 | .nav li ul a { |
122 | color: #524D4D; |
123 | display: block; |
124 | font-weight: normal; |
125 | padding: 7px 10px; |
126 | text-align: left; |
127 | } |
128 | .nav li ul a:hover { |
129 | background-color: #E1DFDF; |
130 | color: #221919; |
131 | text-decoration: none; |
132 | } |
133 | .nav li ul a:active { |
134 | background-color: #CB2027; |
135 | color: #FFFFFF; |
136 | } |
137 | .nav .div a { |
138 | border-top: 1px solid #E1DFDF; |
139 | } |
140 | .nav > li:last-child ul { |
141 | left: auto; |
142 | right: 0; |
143 | } |
As you see – this is usual UL-LI based dropdown menu here. Well, now, the most interesting styles for today (CSS3-based upload form):
01 | /* popup upload form styles */ |
02 | .overlay { |
03 | background-color: #FFFFFF; |
04 | bottom: 0; |
05 | display: none; |
06 | left: 0; |
07 | opacity: 0.8; |
08 | position: fixed; |
09 | right: 0; |
10 | top: 0; |
11 | z-index: 9; |
12 | } |
13 | .overlay:target { |
14 | display: block; |
15 | } |
16 | .popup { |
17 | background: none repeat scroll 0 0 #FCF9F9; |
18 | border: 1px solid #F7F5F5; |
19 | box-shadow: 0 2px 5px rgba(34, 25, 25, 0.5); |
20 | display: inline-block; |
21 | left: 50%; |
22 | padding: 30px 30px 20px; |
23 | position: fixed; |
24 | top: 40%; |
25 | visibility: hidden; |
26 | width: 550px; |
27 | z-index: 10; |
28 | -webkit-transform: translate(-50%, -50%); |
29 | -moz-transform: translate(-50%, -50%); |
30 | -ms-transform: translate(-50%, -50%); |
31 | -o-transform: translate(-50%, -50%); |
32 | transform: translate(-50%, -50%); |
33 | -webkit-transition: all 0.3s ease-in-out 0s; |
34 | -moz-transition: all 0.3s ease-in-out 0s; |
35 | -ms-transition: all 0.3s ease-in-out 0s; |
36 | -o-transition: all 0.3s ease-in-out 0s; |
37 | transition: all 0.3s ease-in-out 0s; |
38 | } |
39 | .overlay:target+.popup { |
40 | top: 50%; |
41 | opacity: 1 ; |
42 | visibility: visible; |
43 | } |
44 | .popup .header { |
45 | background-color: #F2F0F0; |
46 | border-bottom: 1px solid #CCCACA; |
47 | margin: -30px -31px 20px; |
48 | padding: 18px 31px 8px; |
49 | position: relative; |
50 | } |
51 | .popup .header h2 { |
52 | color: #8C7E7E; |
53 | font-size: 21px; |
54 | line-height: 1em; |
55 | margin: 0 37px 0 0; |
56 | text-shadow: 0 1px #FFFFFF; |
57 | } |
58 | .popup .close { |
59 | background: -webkit-linear-gradient(#FFFCFC, #F0EDED) repeat scroll 0 0 transparent; |
60 | background: -moz-linear-gradient(#FFFCFC, #F0EDED) repeat scroll 0 0 transparent; |
61 | background: linear-gradient(#FFFCFC, #F0EDED) repeat scroll 0 0 transparent; |
62 | border-left: 1px solid rgba(34, 25, 25, 0.15); |
63 | bottom: 0; |
64 | box-shadow: 0 1px 2px #FFFFFF inset; |
65 | color: #BBBBBB; |
66 | display: block; |
67 | font-size: 50px; |
68 | line-height: 42px; |
69 | position: absolute; |
70 | right: 0; |
71 | text-align: center; |
72 | text-decoration: none; |
73 | top: 0; |
74 | width: 57px; |
75 | z-index: 1; |
76 | } |
77 | .popup form input[type="file"] { |
78 | font-size: 18px; |
79 | } |
This is a similar method as we used in our previous lesson (CSS3 Modal Popups). Well, now I have to give you final styles for the main container (for pin elements) and for single pin:
001 | /* photo pins - general styles */ |
002 | .main_container { |
003 | margin: 0 auto; |
004 | padding: 10px 10px 0; |
005 | position: relative; |
006 | } |
007 | .button { |
008 | background-color: #F0EDED; |
009 | background-image: -webkit-linear-gradient(center top , #FDFAFB, #F9F7F7 50%, #F6F3F4 50%, #F0EDED); |
010 | background-image: -moz-linear-gradient(center top , #FDFAFB, #F9F7F7 50%, #F6F3F4 50%, #F0EDED); |
011 | background-image: linear-gradient(center top , #FDFAFB, #F9F7F7 50%, #F6F3F4 50%, #F0EDED); |
012 | border: 1px solid #BBBBBB; |
013 | border-radius: 6px 6px 6px 6px; |
014 | color: #524D4D; |
015 | cursor: pointer; |
016 | display: inline-block; |
017 | float: right; |
018 | font-weight: bold; |
019 | line-height: 1em; |
020 | margin: 0; |
021 | padding: 5px 9px; |
022 | text-align: center; |
023 | text-shadow: 0 1px rgba(255, 255, 255, 0.9); |
024 | -webkit-transition: all 0.2s ease-in-out 0s; |
025 | -moz-transition: all 0.2s ease-in-out 0s; |
026 | -ms-transition: all 0.2s ease-in-out 0s; |
027 | -o-transition: all 0.2s ease-in-out 0s; |
028 | transition: all 0.2s ease-in-out 0s; |
029 | } |
030 | .button:hover { |
031 | box-shadow: 0 1px rgba(255, 255, 255, 0.35) inset, 0 0 0 1px rgba(140, 126, 126, 0.5), 0 1px 2px rgba(35, 24, 24, 0.75); |
032 | } |
033 | .button.disabled, .button[disabled] { |
034 | background: none repeat scroll 0 0 #F2F0F0; |
035 | border-color: #D1CDCD; |
036 | color: #D1CDCD; |
037 | cursor: default; |
038 | text-shadow: 0 -1px rgba(34, 25, 25, 0.01); |
039 | } |
040 | /* single pin styles */ |
041 | .pin { |
042 | background-color: #FFFFFF; |
043 | box-shadow: 0 1px 3px rgba(34, 25, 25, 0.4); |
044 | float: left; |
045 | font-size: 11px; |
046 | margin: 0 15px 15px 0; |
047 | padding: 15px 15px 0; |
048 | position: relative; |
049 | width: 192px; |
050 | } |
051 | .pin .holder { |
052 | position: relative; |
053 | } |
054 | .pin .actions { |
055 | left: -8px; |
056 | position: absolute; |
057 | top: -8px; |
058 | z-index: 3; |
059 | } |
060 | .pin .actions a { |
061 | clear: none; |
062 | display: none; |
063 | float: left; |
064 | margin: 0 5px 0 0; |
065 | } |
066 | .pin:hover .actions a { |
067 | display: block; |
068 | } |
069 | .pin .image { |
070 | background-color: #F2F0F0; |
071 | cursor: -webkit-zoom-in; |
072 | cursor: -moz-zoom-in; |
073 | text-decoration: none; |
074 | } |
075 | .pin .image img { |
076 | max-width: 192px; |
077 | min-height: 75px; |
078 | opacity: 1; |
079 | } |
080 | .pin .desc { |
081 | margin: 10px 0 5px; |
082 | overflow: hidden; |
083 | word-wrap: break-word; |
084 | } |
085 | .pin .info { |
086 | color: #8C7E7E; |
087 | line-height: 1.35em; |
088 | margin: 0 0 0.8em; |
089 | overflow: hidden; |
090 | } |
091 | .pin .info span { |
092 | float: left; |
093 | margin-right: 10px; |
094 | } |
095 | .comment { |
096 | background-color: #F2F0F0; |
097 | border-top: 1px solid #D9D4D4; |
098 | box-shadow: 0 1px #FCFAFA inset; |
099 | margin: 0 -15px; |
100 | overflow: hidden; |
101 | padding: 10px 15px; |
102 | } |
103 | .comment textarea { |
104 | background-color: #FCF9F9; |
105 | border: 1px solid #CCCCCC; |
106 | color: #8C7E7E; |
107 | font-size: 11px; |
108 | height: 21px; |
109 | line-height: 1em; |
110 | margin-bottom: 6px; |
111 | padding: 4px 3px 3px; |
112 | resize: none; |
113 | width: 185px; |
114 | } |
115 | .comment textarea:focus { |
116 | background-color: #FFFFFF; |
117 | box-shadow: 0 1px 1px rgba(34, 29, 29, 0.1) inset; |
118 | } |
Step 3. JS
We have just got over our big step with styles, and now I would like to give you a small piece of javascript:
js/script.js
01 | $(document).ready(function(){ |
02 | // masonry initialization |
03 | $('.main_container').masonry({ |
04 | // options |
05 | itemSelector : '.pin', |
06 | isAnimated: true, |
07 | isFitWidth: true |
08 | }); |
09 | // onclick event handler (for comments) |
10 | $('.comment_tr').click(function () { |
11 | $(this).toggleClass('disabled'); |
12 | $(this).parent().parent().parent().find('form').slideToggle(250, function () { |
13 | $('.main_container').masonry(); |
14 | }); |
15 | }); |
16 | }); |
As you see – it is very easy to use masonry jQuery plugin, in the same time it does a great job – it aligns elements (pins) over the page.
Live Demo
Conclusion
We have just finished our first lesson where we started making Pinterest-like script. I hope that you like it. It would be kind of you to share our materials with your friends. Good luck and welcome back!







