├── .gitignore ├── CNAME ├── README.md ├── app ├── .DS_Store ├── css │ ├── reset.css │ └── style.css ├── index.html └── js │ └── index.js ├── comparison ├── .DS_Store ├── with-responsify-js │ ├── index.html │ └── responsify.js ├── with.gif ├── without-responsify-js-bg │ ├── .DS_Store │ └── index.html ├── without-responsify-js │ ├── .DS_Store │ └── index.html └── without.gif ├── css ├── reset.css └── style.css ├── favicon.png ├── images ├── 1.jpg ├── 10.jpg ├── 11.jpg ├── 12.jpg ├── 13.jpg ├── 15.jpg ├── 16.jpg ├── 17.jpg ├── 18.jpg ├── 19.jpg ├── 2.jpg ├── 20.jpg ├── 21.jpg ├── 22.jpg ├── 23.jpg ├── 24.jpg ├── 25.jpg ├── 26.jpg ├── 27.jpg ├── 28.jpg ├── 29.jpg ├── 3.jpg ├── 30.jpg ├── 31.jpg ├── 4.jpg ├── 5.jpg ├── 6.jpg ├── 7.jpg ├── 8.jpg └── 9.jpg ├── index.html ├── js └── index.js ├── license.txt ├── responsify.js └── responsify.min.js /.gitignore: -------------------------------------------------------------------------------- 1 | .sass-cache 2 | *.css.map 3 | -------------------------------------------------------------------------------- /CNAME: -------------------------------------------------------------------------------- 1 | responsifyjs.space -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Responsify.js 2 | 3 | `A jquery plugin that makes images truly responsive, without sacrificing anyone's face :D` 4 | 5 | When images are used in a responsive container on web design, because of the container can change to any width:height ratio, a group shot could end up being cut off on people's faces, a nice photograph following "rule of third" could end up with no object in view. Responsive images face the challenge of how to keep the focused objects/area in view, this jquery plugin is here to solve the problem. 6 | 7 | ### Download 8 | * [responsify.js](https://raw.githubusercontent.com/wentin/ResponsifyJS/master/responsify.js) 9 | * [responsify.min.js](https://raw.githubusercontent.com/wentin/ResponsifyJS/master/responsify.min.js) 10 | 11 | ### Demo 12 | 13 | [https://responsifyjs.wentin.net/](https://responsifyjs.wentin.net/) 14 | 15 | ### App 16 | 17 | [https://responsifyjs.wentin.net/app](https://responsifyjs.wentin.net/app) 18 | 19 | Use this interactive web app to generate the focus area data 20 | 21 | ### What it does 22 | 23 | Responsify.js does the following: 24 | 1. It allows you define a focus area on an image using `data-focus-xxx` tag 25 | 2. It takes in the focus area data from the image, calcuate the image's container's size, resize and position the image accordingly, make sure the focus area is always in view and in the best position possible. 26 | 27 | * Responsive image **with** responsify.js 28 | 29 | ![with-s](https://cloud.githubusercontent.com/assets/2474904/11459461/dccd59b6-96a4-11e5-81c6-5b16c7d30a23.gif) [play it yourself](http://wentin.github.io/ResponsifyJS/comparison/with-responsify-js/) 30 | 31 | * Responsive image **without** responsify.js 32 | 33 | ![without-s](https://cloud.githubusercontent.com/assets/2474904/11459460/dccd53bc-96a4-11e5-8a33-bea161ef60a9.gif) [play it yourself](http://wentin.github.io/ResponsifyJS/comparison/without-responsify-js/) 34 | 35 | ### How to use 36 | 1. Use this interactive web app to generate the focus area data [http://responsifyjs.space/app/](http://responsifyjs.space/app/) 37 | 38 | ``` 39 | 41 | ``` 42 | `data-focus-left` is the focus area's left position comparing to the image's full width, in decimal. For example, if the full width is 300px, the focus area's left is 90, then the `data-focus-left` should be 90/300 = `0.3`. Same logic applies to other three data attributes. 43 | 44 | 2. Embed the responsify.js in the html 45 | 46 | ``` 47 | 48 | ``` 49 | 3. Call responsify function when window object is loaded 50 | 51 | ``` 52 | $(window).load(function() { 53 | $('img').responsify(); 54 | }); 55 | ``` 56 | 4. Call responsify function again when the window is being resized (optional) 57 | 58 | ``` 59 | $(window).resize(function(){ 60 | $('img').responsify(); 61 | }) 62 | ``` 63 | 64 | 65 | ###Contact Me 66 | * Follow [@DesignJokes](http://twitter.com/DesignJokes) on Twitter 67 | * Email 68 | 69 | ###Other Project by Wentin 70 | * [Type Detail](http://typedetail.com/) 71 | * [underline.js](https://github.com/wentin/underlineJS) 72 | -------------------------------------------------------------------------------- /app/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wentin/ResponsifyJS/53230e7d0b318d671c2000b02aa8dc9e5af8e563/app/.DS_Store -------------------------------------------------------------------------------- /app/css/reset.css: -------------------------------------------------------------------------------- 1 | html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video{margin:0;padding:0;border:0;font-size:100%;font:inherit;vertical-align:baseline}article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{display:block}body{line-height:1}ol,ul{list-style:none}blockquote,q{quotes:none}blockquote:before,blockquote:after,q:before,q:after{content:'';content:none}table{border-collapse:collapse;border-spacing:0} 2 | -------------------------------------------------------------------------------- /app/css/style.css: -------------------------------------------------------------------------------- 1 | .wrapper { 2 | width: 640px; 3 | margin: 20px auto; 4 | } 5 | .canvasWrapper { 6 | width: 640px; 7 | height: 640px; 8 | background: #FFFFFF; 9 | box-shadow: 0px 4px 16px 0px rgba(0,0,0,0.10); 10 | border-radius: 8px; 11 | position: relative; 12 | } 13 | .canvasWrapper p { 14 | display: inline-block; 15 | line-height: 20px; 16 | font-family: 'Source Code Pro'; 17 | font-size: 12px; 18 | color: #222222; 19 | top: 290px; 20 | left: 220px; 21 | position: relative; 22 | } 23 | canvas { 24 | cursor: crosshair; 25 | position: absolute; 26 | z-index: 999; 27 | top: 19px; 28 | left: 19px; 29 | border: 1px solid #DDDDDD; 30 | } 31 | /*#button { 32 | display: inline-block; 33 | font-family: 'Source Code Pro'; 34 | font-size: 12px; 35 | color: #F7F7F7; 36 | line-height: 40px; 37 | background: #222222; 38 | border-radius: 4px; 39 | padding: 0 20px; 40 | position: absolute; 41 | right: -204px; 42 | bottom: 0px; 43 | cursor: pointer; 44 | }*/ 45 | textarea { 46 | font-family: 'Source Code Pro'; 47 | color: #222222; 48 | font-size: 12px; 49 | line-height: 20px; 50 | width: 600px; 51 | padding: 16px 20px; 52 | margin-top: 20px; 53 | border: none; 54 | background: #F7F7F7; 55 | border-radius: 4px; 56 | } -------------------------------------------------------------------------------- /app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ResponsifyJS : Interative Image Focus Area app 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 |

16 | 1. Drag & drop image
17 | 2. Select area
18 | 3. Copy the generated code 19 | 20 |

21 | 22 |
23 | 25 |
26 | 27 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /app/js/index.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | var canvas = document.getElementById("my-canvas"), 3 | context = canvas.getContext("2d"), 4 | rect = {}, 5 | drag = false, 6 | img = document.createElement("img"), 7 | imageName, 8 | left = 0, 9 | top = 0, 10 | right = 1, 11 | bottom = 1, 12 | canvasWidth = canvas.width, 13 | canvasHeight = canvas.height, 14 | imgWidth = canvasWidth, 15 | imgHeight = canvasHeight, 16 | clearCanvas = function() { 17 | // context.clearRect(0, 0, canvasWidth, canvasHeight); 18 | context.fillStyle = "#ffffff"; 19 | context.fillRect(0, 0, canvasWidth, canvasHeight); 20 | }; 21 | 22 | function drawImg() { 23 | clearCanvas(); 24 | context.drawImage(img, 0, 0, imgWidth, imgHeight); 25 | } 26 | 27 | function updateResult(name, left, top, right, bottom) { 28 | var dataFocus = ''; 34 | document.getElementById('code').value = dataFocus; 35 | } 36 | 37 | // Image for loading 38 | img.addEventListener("load", function() { 39 | var ratio = img.naturalWidth / img.naturalHeight; 40 | if (img.naturalHeight > canvasHeight && ratio < 1) { 41 | imgWidth = canvasHeight * ratio; 42 | imgHeight = canvasHeight; 43 | } else if (img.naturalWidth > canvasWidth && ratio > 1) { 44 | imgWidth = canvasWidth; 45 | imgHeight = canvasWidth / ratio; 46 | } else { 47 | imgWidth = img.naturalWidth; 48 | imgHeight = img.naturalHeight; 49 | } 50 | drawImg(); 51 | }, false); 52 | 53 | // To enable drag and drop 54 | canvas.addEventListener("dragover", function(evt) { 55 | evt.preventDefault(); 56 | }, false); 57 | 58 | // Handle dropped image file - only Firefox and Google Chrome 59 | canvas.addEventListener("drop", function(evt) { 60 | var files = evt.dataTransfer.files; 61 | if (files.length > 0) { 62 | var file = files[0]; 63 | if (typeof FileReader !== "undefined" && file.type.indexOf("image") != -1) { 64 | var reader = new FileReader(); 65 | // Note: addEventListener doesn't work in Google Chrome for this event 66 | reader.onload = function(evt) { 67 | img.src = evt.target.result; 68 | }; 69 | reader.readAsDataURL(file); 70 | imageName = file.name; 71 | updateResult(imageName, 0, 0, 1, 1); 72 | } 73 | } 74 | evt.preventDefault(); 75 | }, false); 76 | 77 | // Detect mousedown 78 | canvas.addEventListener("mousedown", function(e) { 79 | rect.startX = e.layerX; 80 | rect.startY = e.layerY; 81 | drag = true; 82 | }, false); 83 | 84 | // Detect mouseup 85 | canvas.addEventListener("mouseup", function(e) { 86 | drag = false; 87 | }, false); 88 | 89 | // Draw, if mouse button is pressed 90 | canvas.addEventListener("mousemove", function(e) { 91 | if (drag) { 92 | drawImg(); 93 | 94 | rect.w = (e.layerX) - rect.startX; 95 | rect.h = (e.layerY) - rect.startY; 96 | left = rect.startX / imgWidth; 97 | top = rect.startY / imgHeight; 98 | right = (rect.w + rect.startX) / imgWidth; 99 | bottom = (rect.h + rect.startY) / imgHeight; 100 | if (imageName) { 101 | updateResult(imageName, left.toFixed(2), top.toFixed(2), right.toFixed(2), bottom.toFixed(2)); 102 | } 103 | context.fillStyle = "rgba(255, 0, 0, 0.3)"; 104 | context.fillRect(rect.startX, rect.startY, rect.w, rect.h); 105 | } 106 | }, false); 107 | 108 | // Save image 109 | /*var saveImage = document.getElementById("button"); 110 | saveImage.addEventListener("click", function(evt) { 111 | window.open(canvas.toDataURL("image/png")); 112 | evt.preventDefault(); 113 | }, false);*/ 114 | })(); 115 | -------------------------------------------------------------------------------- /comparison/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wentin/ResponsifyJS/53230e7d0b318d671c2000b02aa8dc9e5af8e563/comparison/.DS_Store -------------------------------------------------------------------------------- /comparison/with-responsify-js/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | responsify.js 6 | 16 | 17 | 18 | 26 | 27 | 28 |
29 | 30 |
31 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /comparison/with-responsify-js/responsify.js: -------------------------------------------------------------------------------- 1 | (function ( $ ) { 2 | $.fn.responsify = function() { 3 | return this.each(function() { 4 | var owdith, oheight, 5 | twidth, theight, 6 | fx1, fy1, fx2, fy2, 7 | width, height, top, left; 8 | 9 | owidth = $(this).width(); 10 | oheight = $(this).height(); 11 | twidth = $(this).parent().width(); 12 | theight = $(this).parent().height(); 13 | fx1 = Number($(this).attr('data-focus-left')); 14 | fy1 = Number($(this).attr('data-focus-top')); 15 | fx2 = Number($(this).attr('data-focus-right')); 16 | fy2 = Number($(this).attr('data-focus-bottom')); 17 | if( owidth/oheight > twidth/theight ) { 18 | var fwidth = (fx2-fx1) * owidth; 19 | if ( fwidth/oheight > twidth/theight ) { 20 | height = oheight*twidth/fwidth; 21 | width = owidth*twidth/fwidth; 22 | left = -fx1*width; 23 | top = (theight-height)/2; 24 | } else { 25 | height = theight; 26 | width = theight*owidth/oheight; 27 | left = twidth/2 - (fx1 + fx2)*width/2; 28 | // if left > 0, it will leave blank on the left, so set it to 0; 29 | left = left>0?0:left; 30 | // if width - left < twidth, it will leave blank on the right, so set left = width - twidth 31 | left = (twidth - left - width)>0?(twidth-width):left 32 | top = 0; 33 | } 34 | } 35 | else { 36 | var fheight = (fy2-fy1) * oheight; 37 | if ( fheight/owidth > theight/twidth ) { 38 | width = owidth*theight/fheight; 39 | height = oheight*theight/fheight; 40 | top = -fy1*height; 41 | left = (twidth-width)/2; 42 | } else { 43 | width = twidth; 44 | height = twidth*oheight/owidth; 45 | top = theight/2 - (fy1 + fy2)*height/2; 46 | // if top > 0, it will leave blank on the top, so set it to 0; 47 | top = top>0?0:top; 48 | // if height - top < theight, it will leave blank on the bottom, so set top = height - theight 49 | top = (theight - top - height)>0?(theight-height):top 50 | left = 0; 51 | } 52 | } 53 | $(this).parent().css({ 54 | "overflow": "hidden" 55 | }) 56 | $(this).css({ 57 | "position": "relative", 58 | "height": height, 59 | "width": width, 60 | "left": left, 61 | "top": top 62 | }) 63 | }); 64 | }; 65 | }( jQuery )); -------------------------------------------------------------------------------- /comparison/with.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wentin/ResponsifyJS/53230e7d0b318d671c2000b02aa8dc9e5af8e563/comparison/with.gif -------------------------------------------------------------------------------- /comparison/without-responsify-js-bg/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wentin/ResponsifyJS/53230e7d0b318d671c2000b02aa8dc9e5af8e563/comparison/without-responsify-js-bg/.DS_Store -------------------------------------------------------------------------------- /comparison/without-responsify-js-bg/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | No responsify.js 6 | 18 | 19 | 20 |
21 |
22 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /comparison/without-responsify-js/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wentin/ResponsifyJS/53230e7d0b318d671c2000b02aa8dc9e5af8e563/comparison/without-responsify-js/.DS_Store -------------------------------------------------------------------------------- /comparison/without-responsify-js/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | No responsify.js 6 | 20 | 21 | 22 |
23 | 24 |
25 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /comparison/without.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wentin/ResponsifyJS/53230e7d0b318d671c2000b02aa8dc9e5af8e563/comparison/without.gif -------------------------------------------------------------------------------- /css/reset.css: -------------------------------------------------------------------------------- 1 | html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video{margin:0;padding:0;border:0;font-size:100%;font:inherit;vertical-align:baseline}article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{display:block}body{line-height:1}ol,ul{list-style:none}blockquote,q{quotes:none}blockquote:before,blockquote:after,q:before,q:after{content:'';content:none}table{border-collapse:collapse;border-spacing:0} 2 | -------------------------------------------------------------------------------- /css/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: 'Source Code Pro'; 3 | } 4 | .clr { 5 | clear: both; 6 | } 7 | header#demo { 8 | /* border: solid 2px wheat; */ 9 | } 10 | .row { 11 | width: 100%; 12 | float: left; 13 | position: relative; 14 | } 15 | .row a { 16 | display: block; 17 | overflow: hidden; 18 | float: left; 19 | box-sizing: border-box; 20 | /* border: solid 2px wheat; */ 21 | background-color: wheat; 22 | } 23 | .img1 { 24 | width: 66.67%; 25 | height: 40vh; 26 | position: relative; 27 | } 28 | .img2 { 29 | width: 33.33%; 30 | height: 40vh; 31 | } 32 | .img3 { 33 | width: 33.33%; 34 | height: 60vh; 35 | } 36 | .img4 { 37 | width: 25%; 38 | height: 60vh; 39 | } 40 | .img5, .img6 { 41 | width: 41.67%; 42 | height: 30vh; 43 | } 44 | .img7 { 45 | height: 70vh; 46 | width: 16.66%; 47 | } 48 | .img8 { 49 | height: 70vh; 50 | width: 16.67%; 51 | } 52 | .img9 { 53 | width: 66.67%; 54 | height: 30vh; 55 | } 56 | .img10 { 57 | width: 41.67%; 58 | height: 40vh; 59 | } 60 | .img11 { 61 | width: 25%; 62 | height: 40vh; 63 | } 64 | header .card { 65 | font-family: 'Source Code Pro'; 66 | position: absolute; 67 | z-index: 9; 68 | } 69 | header .card h1 { 70 | display: inline-block; 71 | border-radius: 32px; 72 | font-weight: bold; 73 | font-size: 20px; 74 | letter-spacing: 0.4px; 75 | line-height: 36px; 76 | padding: 0 18px; 77 | } 78 | header .instruction.card { 79 | left: 20px; 80 | top: 20px; 81 | } 82 | header .instruction.card h1 { 83 | background: #35195B; 84 | color: #F2EDC5; 85 | } 86 | header .instruction.card p { 87 | color: #35195B; 88 | background: rgba(242, 237, 197, 0.85); 89 | border-radius: 4px; 90 | font-size: 12px; 91 | line-height: 20px; 92 | width: 364px; 93 | padding: 12px 18px; 94 | margin-top: 6px; 95 | } 96 | header .instruction.card p strong { 97 | font-weight: bold; 98 | } 99 | header .git.card { 100 | right: 20px; 101 | top: 20px; 102 | } 103 | header .git.card h1 { 104 | background: #45252A; 105 | color: #FFF4E2; 106 | float: left; 107 | } 108 | header .app.card { 109 | left: 20px; 110 | top: 20px; 111 | } 112 | header .app.card h1 { 113 | background: #884F67; 114 | color: #FFFEDF; 115 | float: left; 116 | } 117 | 118 | header .share.card { 119 | right: 20px; 120 | top: 20px; 121 | } 122 | header .share.card h1 { 123 | background: #320F0B; 124 | color: #FFDF73; 125 | float: left; 126 | } 127 | .icon { 128 | display: inline-block; 129 | width: 36px; 130 | height: 36px; 131 | border-radius: 50%; 132 | text-decoration: none; 133 | box-sizing: border-box; 134 | } 135 | .icon:hover { 136 | text-decoration: none; 137 | opacity: 0.6; 138 | } 139 | .icon:before { 140 | font-size: 18px; 141 | display: block; 142 | width: 34px; 143 | text-align: center; 144 | line-height: 34px; 145 | font-family: 'responsifyjs' !important; 146 | speak: none; 147 | font-style: normal; 148 | font-weight: normal; 149 | font-variant: normal; 150 | text-transform: none; 151 | -webkit-font-smoothing: antialiased; 152 | } 153 | .card .icon.github { 154 | background: #FFF4E2; 155 | border: solid 1px #45252A; 156 | } 157 | .icon.github:before { 158 | content: "\e902"; 159 | color: #45252A; 160 | } 161 | .icon.githubStar { 162 | background: white; 163 | border: solid 1px black; 164 | } 165 | .icon.githubStar:before { 166 | content: "\e905"; 167 | color: black; 168 | } 169 | .icon.export { 170 | background: #FFFEDF; 171 | border: solid 1px #884F67; 172 | } 173 | .icon.export:before { 174 | content: "\e901"; 175 | color: #884F67; 176 | } 177 | .icon.facebook { 178 | background: #FFDF73; 179 | border: solid 1px #320F0B; 180 | } 181 | .icon.facebook:before { 182 | content: "\e903"; 183 | color: #320F0B; 184 | } 185 | .icon.twitter { 186 | background: #FFDF73; 187 | border: solid 1px #320F0B; 188 | } 189 | .icon.twitter:before { 190 | content: "\e900"; 191 | color: #320F0B; 192 | } 193 | main { 194 | padding-top: 32px; 195 | width: 720px; 196 | margin: 0 auto; 197 | font-family: 'Source Code Pro'; 198 | } 199 | main h1 { 200 | font-weight: bold; 201 | font-size: 20px; 202 | color: #FFFFFF; 203 | letter-spacing: 0.4px; 204 | background: #000000; 205 | border-radius: 32px; 206 | line-height: 36px; 207 | height: 36px; 208 | width: 200px; 209 | margin: 0 auto; 210 | text-align: center; 211 | margin-bottom: 32px; 212 | } 213 | main p { 214 | font-weight: regular; 215 | font-size: 16px; 216 | color: #000000; 217 | line-height: 24px; 218 | margin-bottom: 16px; 219 | } 220 | main a { 221 | color: #3D76C2; 222 | text-decoration: none; 223 | word-wrap: break-word; 224 | } 225 | a:hover { 226 | text-decoration: underline; 227 | } 228 | main ol, 229 | main ul { 230 | line-height: 24px; 231 | } 232 | main ol li{ 233 | list-style: decimal; 234 | list-style-position: inside; 235 | margin-bottom: 16px; 236 | } 237 | main ul li { 238 | list-style: disc; 239 | list-style-position: inside; 240 | margin-bottom: 16px; 241 | } 242 | main h3 { 243 | font-weight: bold; 244 | font-size: 18px; 245 | color: #000000; 246 | line-height: 24px; 247 | margin-bottom: 16px; 248 | margin-top: 32px; 249 | } 250 | pre { 251 | font-size: 12px; 252 | line-height: 20px; 253 | padding: 16px 20px; 254 | background: #F7F7F7; 255 | border-radius: 4px; 256 | margin-bottom: 16px; 257 | word-wrap: break-word; 258 | } 259 | .gifs { 260 | width: 1000px; 261 | margin: 32px auto; 262 | } 263 | .gifs h2 { 264 | text-align: center; 265 | margin-top: 8px; 266 | font-weight: 400; 267 | } 268 | .gifs h2 strong { 269 | font-weight: bold; 270 | } 271 | .gifs .with, .gifs .without { 272 | width: 480px; 273 | height: 382px; 274 | float: left; 275 | } 276 | .gifs .with { 277 | margin-right: 40px; 278 | } 279 | footer { 280 | width: 720px; 281 | margin: 32px auto; 282 | } 283 | footer .share { 284 | text-align: center; 285 | padding-bottom: 60px; 286 | } 287 | footer .share h3 { 288 | font-weight: bold; 289 | font-size: 18px; 290 | color: #000000; 291 | line-height: 24px; 292 | margin-bottom: 16px; 293 | margin-top: 32px; 294 | } 295 | footer .share .icon { 296 | width: 80px; 297 | height: 80px; 298 | box-sizing: border-box; 299 | background-color: #fff; 300 | border: solid 1px black; 301 | } 302 | footer .share .icon.facebook { 303 | margin-right: 10px; 304 | } 305 | footer .share .icon:before { 306 | color: black; 307 | font-size: 32px; 308 | width: 80px; 309 | line-height: 80px; 310 | } 311 | .overlay { 312 | display: none; 313 | z-index: 999; 314 | position: fixed; 315 | top: 0; 316 | left: 0; 317 | width: 100%; 318 | height: 100%; 319 | background-color: rgba(0,0,0,0.2); 320 | transition: all 0.4s ease; 321 | } 322 | .module { 323 | position: relative; 324 | width: 400px; 325 | margin: 0 auto; 326 | top: -200px; 327 | transition: all 0.4s ease; 328 | } 329 | .module .close.icon { 330 | position: absolute; 331 | box-sizing: border-box; 332 | right:-36px; 333 | top: 0; 334 | width: 36px; 335 | height: 36px; 336 | background-color: #FFFEDF; 337 | border: solid 1px #884F67; 338 | border-radius: 50%; 339 | cursor: pointer; 340 | } 341 | .module .close.icon:before { 342 | content: "\e906"; 343 | color: #884F67; 344 | } 345 | .module h1 { 346 | font-weight: bold; 347 | font-size: 20px; 348 | letter-spacing: 0.4px; 349 | line-height: 36px; 350 | padding: 0 18px; 351 | box-sizing: border-box; 352 | border-radius: 32px; 353 | background: #884F67; 354 | color: #FFFEDF; 355 | } 356 | .module .moduleContent { 357 | color: #884F67; 358 | background: #FFFEDF; 359 | border-radius: 4px; 360 | font-size: 12px; 361 | line-height: 20px; 362 | width: 364px; 363 | padding: 12px 18px; 364 | margin-top: 6px; 365 | text-align: center; 366 | } 367 | .module .moduleContent p { 368 | text-align: left; 369 | margin-bottom: 16px; 370 | } 371 | .module .moduleContent .icon { 372 | background: #FFFEDF; 373 | border: solid 1px #884F67; 374 | width: 80px; 375 | height: 80px; 376 | margin-right: 10px; 377 | box-sizing: content-box; 378 | } 379 | .module .moduleContent .icon:before { 380 | color: #884F67; 381 | font-size: 32px; 382 | width: 80px; 383 | line-height: 80px; 384 | } 385 | body.overlayOn .overlay { 386 | display: block; 387 | } 388 | body.overlayOn .module { 389 | top: 200px; 390 | } 391 | header, main, footer { 392 | transition: all 0.4s ease; 393 | } 394 | body.overlayOn header, 395 | body.overlayOn main, 396 | body.overlayOn footer { 397 | -webkit-filter: blur(5px); 398 | filter: blur(5px); 399 | } 400 | 401 | 402 | @media screen and (max-width: 1040px) { 403 | .gifs { 404 | width: 92%; 405 | margin-left: 4%; 406 | margin-right: 4%; 407 | } 408 | .gifs .with, .gifs .without { 409 | width: 48%; 410 | height: auto; 411 | float: left; 412 | } 413 | .gifs div img { 414 | width: 100%; 415 | height: auto; 416 | } 417 | .gifs .with { 418 | margin-right: 4%; 419 | } 420 | } 421 | 422 | @media screen and (min-width: 320px) and (max-width: 760px) { 423 | .img1 { 424 | width: 33.33%; 425 | height: 30vh; 426 | } 427 | .img2 { 428 | width: 66.67%; 429 | height: 30vh; 430 | } 431 | .img3 { 432 | width: 33.33%; 433 | height: 40vh; 434 | } 435 | .img4 { 436 | width: 33.33%; 437 | height: 40vh; 438 | } 439 | .img5 { 440 | width: 33.33%; 441 | height: 20vh; 442 | } 443 | .img6 { 444 | width: 33.33%; 445 | height: 20vh; 446 | } 447 | .img7 { 448 | width: 25%; 449 | height: 50vh; 450 | } 451 | .img8 { 452 | width: 25%; 453 | height: 50vh; 454 | } 455 | .img9 { 456 | width: 25%; 457 | height: 30vh; 458 | } 459 | .img10 { 460 | width: 25%; 461 | height: 30vh; 462 | } 463 | .img11 { 464 | width: 50%; 465 | height: 20vh; 466 | } 467 | header .instruction.card p { 468 | width: calc(100% - 20px); 469 | box-sizing: border-box; 470 | margin-top: 8px; 471 | } 472 | main { 473 | width: 92%; 474 | margin: 0 4%; 475 | } 476 | footer { 477 | width: 92%; 478 | margin: 0 4%; 479 | } 480 | } -------------------------------------------------------------------------------- /favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wentin/ResponsifyJS/53230e7d0b318d671c2000b02aa8dc9e5af8e563/favicon.png -------------------------------------------------------------------------------- /images/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wentin/ResponsifyJS/53230e7d0b318d671c2000b02aa8dc9e5af8e563/images/1.jpg -------------------------------------------------------------------------------- /images/10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wentin/ResponsifyJS/53230e7d0b318d671c2000b02aa8dc9e5af8e563/images/10.jpg -------------------------------------------------------------------------------- /images/11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wentin/ResponsifyJS/53230e7d0b318d671c2000b02aa8dc9e5af8e563/images/11.jpg -------------------------------------------------------------------------------- /images/12.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wentin/ResponsifyJS/53230e7d0b318d671c2000b02aa8dc9e5af8e563/images/12.jpg -------------------------------------------------------------------------------- /images/13.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wentin/ResponsifyJS/53230e7d0b318d671c2000b02aa8dc9e5af8e563/images/13.jpg -------------------------------------------------------------------------------- /images/15.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wentin/ResponsifyJS/53230e7d0b318d671c2000b02aa8dc9e5af8e563/images/15.jpg -------------------------------------------------------------------------------- /images/16.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wentin/ResponsifyJS/53230e7d0b318d671c2000b02aa8dc9e5af8e563/images/16.jpg -------------------------------------------------------------------------------- /images/17.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wentin/ResponsifyJS/53230e7d0b318d671c2000b02aa8dc9e5af8e563/images/17.jpg -------------------------------------------------------------------------------- /images/18.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wentin/ResponsifyJS/53230e7d0b318d671c2000b02aa8dc9e5af8e563/images/18.jpg -------------------------------------------------------------------------------- /images/19.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wentin/ResponsifyJS/53230e7d0b318d671c2000b02aa8dc9e5af8e563/images/19.jpg -------------------------------------------------------------------------------- /images/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wentin/ResponsifyJS/53230e7d0b318d671c2000b02aa8dc9e5af8e563/images/2.jpg -------------------------------------------------------------------------------- /images/20.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wentin/ResponsifyJS/53230e7d0b318d671c2000b02aa8dc9e5af8e563/images/20.jpg -------------------------------------------------------------------------------- /images/21.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wentin/ResponsifyJS/53230e7d0b318d671c2000b02aa8dc9e5af8e563/images/21.jpg -------------------------------------------------------------------------------- /images/22.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wentin/ResponsifyJS/53230e7d0b318d671c2000b02aa8dc9e5af8e563/images/22.jpg -------------------------------------------------------------------------------- /images/23.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wentin/ResponsifyJS/53230e7d0b318d671c2000b02aa8dc9e5af8e563/images/23.jpg -------------------------------------------------------------------------------- /images/24.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wentin/ResponsifyJS/53230e7d0b318d671c2000b02aa8dc9e5af8e563/images/24.jpg -------------------------------------------------------------------------------- /images/25.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wentin/ResponsifyJS/53230e7d0b318d671c2000b02aa8dc9e5af8e563/images/25.jpg -------------------------------------------------------------------------------- /images/26.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wentin/ResponsifyJS/53230e7d0b318d671c2000b02aa8dc9e5af8e563/images/26.jpg -------------------------------------------------------------------------------- /images/27.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wentin/ResponsifyJS/53230e7d0b318d671c2000b02aa8dc9e5af8e563/images/27.jpg -------------------------------------------------------------------------------- /images/28.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wentin/ResponsifyJS/53230e7d0b318d671c2000b02aa8dc9e5af8e563/images/28.jpg -------------------------------------------------------------------------------- /images/29.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wentin/ResponsifyJS/53230e7d0b318d671c2000b02aa8dc9e5af8e563/images/29.jpg -------------------------------------------------------------------------------- /images/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wentin/ResponsifyJS/53230e7d0b318d671c2000b02aa8dc9e5af8e563/images/3.jpg -------------------------------------------------------------------------------- /images/30.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wentin/ResponsifyJS/53230e7d0b318d671c2000b02aa8dc9e5af8e563/images/30.jpg -------------------------------------------------------------------------------- /images/31.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wentin/ResponsifyJS/53230e7d0b318d671c2000b02aa8dc9e5af8e563/images/31.jpg -------------------------------------------------------------------------------- /images/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wentin/ResponsifyJS/53230e7d0b318d671c2000b02aa8dc9e5af8e563/images/4.jpg -------------------------------------------------------------------------------- /images/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wentin/ResponsifyJS/53230e7d0b318d671c2000b02aa8dc9e5af8e563/images/5.jpg -------------------------------------------------------------------------------- /images/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wentin/ResponsifyJS/53230e7d0b318d671c2000b02aa8dc9e5af8e563/images/6.jpg -------------------------------------------------------------------------------- /images/7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wentin/ResponsifyJS/53230e7d0b318d671c2000b02aa8dc9e5af8e563/images/7.jpg -------------------------------------------------------------------------------- /images/8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wentin/ResponsifyJS/53230e7d0b318d671c2000b02aa8dc9e5af8e563/images/8.jpg -------------------------------------------------------------------------------- /images/9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wentin/ResponsifyJS/53230e7d0b318d671c2000b02aa8dc9e5af8e563/images/9.jpg -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ResponsifyJS – A jquery plugin that makes images truly responsive, without sacrificing anyone's face. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 |
19 |
20 |

DEMO

21 |

Instruction:
22 | (If on desktop) Resize the browser window to see how the images adapt to responsive layout; click on images to see the original image in a new tab.

23 |
24 |
25 |

GITHUB

26 | 27 |
28 | 29 | 30 | 31 | 32 | 33 | 34 |
35 | 49 |
50 |
51 |

APP

52 | 53 |
54 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 |
76 |
77 | 78 |
79 |
80 | 81 |

Responsive image with responsify.js

82 |
83 |
84 | 85 |

Responsive image without responsify.js

86 |
87 |
88 |
89 |
90 |
91 |

Responsify.js

92 | 93 |

A jquery plugin that makes images truly responsive, without sacrificing anyone's face :D

94 | 95 |

When images are used in a responsive container on web design, because of the container can change to any width:height ratio, a group shot could end up being cut off on people's faces, a nice photograph following "rule of third" could end up with no object in view. Responsive images face the challenge of how to keep the focused objects/area in view, this jquery plugin is here to solve the problem.

96 | 97 |

Download

98 | 99 | 103 | 104 |

Demo

105 | 106 |

http://responsifyjs.space/#demo

107 | 108 |

App

109 | 110 |

http://responsifyjs.space/app

111 | 112 |

Use this interactive web app to generate the focus area data

113 | 114 |

What it does

115 | 116 |

Responsify.js does the following:

117 | 118 |
    119 |
  1. It allows you define a focus area on an image using data-focus-xxx tag
  2. 120 |
  3. It takes in the focus area data from the image, calcuate the image's container's size, resize and position the image accordingly, make sure the focus area is always in view and in the best position possible.
  4. 121 |
122 | 123 |

Responsive image with responsify.js

124 | 125 | 128 | 129 |

Responsive image without responsify.js

130 | 131 | 134 | 135 |

How to use

136 | 137 |
    138 |
  1. Use this interactive web app to generate the focus area data http://responsifyjs.space/app/

    139 | 140 |
      <img src="image.png" alt="" 
    141 |   data-focus-left=".30" data-focus-top=".12" data-focus-right=".79" data-focus-bottom=".66" />
    142 | 
    143 | 144 |

    data-focus-left is the focus area's left position comparing to the image's full width, in decimal. For example, if the full width is 300px, the focus area's left is 90, then the data-focus-left should be 90/300 = 0.3. Same logic applies to other three data attributes.

  2. 145 |
  3. Embed the responsify.js in the html

    146 | 147 |
      <script src="responsify.js"></script>
    148 | 
  4. 149 |
  5. Call responsify function when window object is loaded

    150 | 151 |
      $(window).load(function() {
    152 |     $('img').responsify();
    153 |   });
    154 | 
  6. 155 |
  7. Call responsify function again when the window is being resized (optional)

    156 | 157 |
      $(window).resize(function(){
    158 |     $('img').responsify();
    159 |   })
    160 | 
  8. 161 |
162 | 163 |

Contact Me

164 | 165 | 169 | 170 |

Other Project by Wentin

171 | 172 | 177 |
178 | 207 |
208 | 218 |
219 | 229 | 230 | 231 | 232 | 233 | -------------------------------------------------------------------------------- /js/index.js: -------------------------------------------------------------------------------- 1 | var isMobile = { 2 | Android: function() { 3 | return navigator.userAgent.match(/Android/i); 4 | }, 5 | BlackBerry: function() { 6 | return navigator.userAgent.match(/BlackBerry/i); 7 | }, 8 | iOS: function() { 9 | return navigator.userAgent.match(/iPhone|iPad|iPod/i); 10 | }, 11 | Opera: function() { 12 | return navigator.userAgent.match(/Opera Mini/i); 13 | }, 14 | Windows: function() { 15 | return navigator.userAgent.match(/IEMobile/i) || navigator.userAgent.match(/WPDesktop/i); 16 | }, 17 | any: function() { 18 | return (isMobile.Android() || isMobile.BlackBerry() || isMobile.iOS() || isMobile.Opera() || isMobile.Windows()); 19 | } 20 | }; 21 | $(window).load(function() { 22 | $('a img').responsify(); 23 | if(readCookie('popupshown') == null && !isMobile.any()){ 24 | setTimeout(function(){ 25 | $('body').addClass('overlayOn'); 26 | }, 45000); 27 | createCookie('popupshown', true, 365); 28 | } 29 | $('.overlay .close').click(function(){ 30 | $('body').removeClass('overlayOn'); 31 | }) 32 | }); 33 | $(window).resize(function(){ 34 | $('a img').responsify(); 35 | }) 36 | 37 | // Cookies 38 | function createCookie(name,value,days) { 39 | if (days) { 40 | var date = new Date(); 41 | date.setTime(date.getTime()+(days*24*60*60*1000)); 42 | var expires = "; expires="+date.toGMTString(); 43 | } 44 | else var expires = ""; 45 | document.cookie = name+"="+value+expires+"; path=/"; 46 | } 47 | 48 | function readCookie(name) { 49 | var nameEQ = name + "="; 50 | var ca = document.cookie.split(';'); 51 | for(var i=0;i < ca.length;i++) { 52 | var c = ca[i]; 53 | while (c.charAt(0)==' ') c = c.substring(1,c.length); 54 | if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length); 55 | } 56 | return null; 57 | } 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Zach Lieberman 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /responsify.js: -------------------------------------------------------------------------------- 1 | (function ( $ ) { 2 | $.fn.responsify = function() { 3 | return this.each(function() { 4 | var owidth, oheight, 5 | twidth, theight, 6 | fx1, fy1, fx2, fy2, 7 | width, height, top, left, 8 | $this = $(this); 9 | 10 | owidth = $this.width(); 11 | oheight = $this.height(); 12 | twidth = $this.parent().width(); 13 | theight = $this.parent().height(); 14 | fx1 = Number($this.attr('data-focus-left')); 15 | fy1 = Number($this.attr('data-focus-top')); 16 | fx2 = Number($this.attr('data-focus-right')); 17 | fy2 = Number($this.attr('data-focus-bottom')); 18 | if( owidth/oheight > twidth/theight ) { 19 | var fwidth = (fx2-fx1) * owidth; 20 | if ( fwidth/oheight > twidth/theight ) { 21 | height = oheight*twidth/fwidth; 22 | width = owidth*twidth/fwidth; 23 | left = -fx1*width; 24 | top = (theight-height)/2; 25 | } else { 26 | height = theight; 27 | width = theight*owidth/oheight; 28 | left = twidth/2 - (fx1 + fx2)*width/2; 29 | // if left > 0, it will leave blank on the left, so set it to 0; 30 | left = left>0?0:left; 31 | // if width - left < twidth, it will leave blank on the right, so set left = width - twidth 32 | left = (twidth - left - width)>0?(twidth-width):left; 33 | top = 0; 34 | } 35 | } 36 | else { 37 | var fheight = (fy2-fy1) * oheight; 38 | if ( fheight/owidth > theight/twidth ) { 39 | width = owidth*theight/fheight; 40 | height = oheight*theight/fheight; 41 | top = -fy1*height; 42 | left = (twidth-width)/2; 43 | } else { 44 | width = twidth; 45 | height = twidth*oheight/owidth; 46 | top = theight/2 - (fy1 + fy2)*height/2; 47 | // if top > 0, it will leave blank on the top, so set it to 0; 48 | top = top>0?0:top; 49 | // if height - top < theight, it will leave blank on the bottom, so set top = height - theight 50 | top = (theight - top - height)>0?(theight-height):top; 51 | left = 0; 52 | } 53 | } 54 | $this.parent().css({ 55 | "overflow": "hidden" 56 | }) 57 | $this.css({ 58 | "position": "relative", 59 | "height": height, 60 | "width": width, 61 | "left": left, 62 | "top": top 63 | }) 64 | }); 65 | }; 66 | }( jQuery )); 67 | -------------------------------------------------------------------------------- /responsify.min.js: -------------------------------------------------------------------------------- 1 | !function(t){t.fn.responsify=function(){return this.each(function(){var e,r,a,i,o,h,n,s,f,u,c,d,p=t(this);if(e=p.width(),r=p.height(),a=p.parent().width(),i=p.parent().height(),o=Number(p.attr("data-focus-left")),h=Number(p.attr("data-focus-top")),n=Number(p.attr("data-focus-right")),s=Number(p.attr("data-focus-bottom")),e/r>a/i){var b=(n-o)*e;b/r>a/i?(u=r*a/b,f=e*a/b,d=-o*f,c=(i-u)/2):(u=i,f=i*e/r,d=a/2-(o+n)*f/2,d=d>0?0:d,d=a-d-f>0?a-f:d,c=0)}else{var l=(s-h)*r;l/e>i/a?(f=e*i/l,u=r*i/l,c=-h*u,d=(a-f)/2):(f=a,u=a*r/e,c=i/2-(h+s)*u/2,c=c>0?0:c,c=i-c-u>0?i-u:c,d=0)}p.parent().css({overflow:"hidden"}),p.css({position:"relative",height:u,width:f,left:d,top:c})})}}(jQuery); 2 | --------------------------------------------------------------------------------