Pos Terbaru Kreatifa Media

Tutorial: 3D-ifying Documents Using CSS Transforms

Sunday, April 7, 2013


Cameron Lakenen from Crocodoc explains how they use SVG to do some fancy 3D effects when converting documents.

Note: the demos in this blog post require IE 9+ (preferably 10), Firefox, or any WebKit browser. If you’re on a mobile device, you might need to click the open in new page button to view the demos properly.


Tutorial App Showcase with Grid Overlay

DEMO      -       DOWNLOAD

A tutorial about creating a simple grid overlay with subtle transitions for an app showcase. 
In this tutorial will be creating a little app showcase with a neat effect. The idea is to show a mobile device with a screenshot of an app and when clicking on the device, a grid appears, showing some more screenshots. The effect is very subtle: the device moves back and the grid fades in and scales up. When clicking on another screenshot, the device image gets updated and the grid disappears again. 

The beautiful iPhone mockup used in the demo is by Jakub Kejha
Let’s get started with the markup.

The Markup

The HTML will consist of a main wrapper that contains a heading, a division for the device and a division for the grid:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<div id="ac-wrapper" class="ac-wrapper">
    <h2>Weatherous <span>Concept & UI Design</span></h2>
    <div class="ac-device">
        <a href="#"><img src="images/screen1.jpg"/></a>
        <h3 class="ac-title">Gentrify small batch umami retro vegan</h3>
    </div>
    <div class="ac-grid">
        <a href="#"><img src="images/screen1.jpg"/><span>Gentrify small batch umami retro vegan</span></a>
        <a href="#"><img src="images/screen2.jpg"/><span>Chambray squid semiotics</span></a>
        <a href="#"><img src="images/screen3.jpg"/><span>Fashion axe blue bottle</span></a>
        <a href="#"><img src="images/screen4.jpg"/><span>Photo booth single-origin coffee</span></a>
        <a href="#"><img src="images/screen5.jpg"/><span>Flexitarian synth keytar blog master</span></a>
        <a href="#"><img src="images/screen6.jpg"/><span>Next level retro flexitarian freegan</span></a>
        <a href="#"><img src="images/screen7.jpg"/><span>Pour-over superious meggings terry</span></a>
        <a href="#"><img src="images/screen8.jpg"/><span>Seitan william vinyl chillwave</span></a>
    </div>
</div>
Once we click on a grid item, we will update the content of the device container. We will also make the span for each grid item appear on hover.
Let’s style everything.

The CSS

Note that the CSS will not contain any vendor prefixes, but you will find them in the files.
In this tutorial we will be going through the style of demo 1.
So let’s start with the main wrapper. This will be the container that will have perspective. The origin will not be in the center but a bit more up:
1
2
3
4
5
6
.ac-wrapper {
    width: 100%;
    position: relative;
    perspective: 1000px;
    perspective-origin: 50% 25%;
}
The heading will be positioned absolutely on the left side of the device:
1
2
3
4
5
6
7
8
9
.ac-wrapper h2 {
    top: 20%;
    width: 50%;
    position: absolute;
    font-weight: 300;
    font-size: 4em;
    text-align: right;
    padding: 0 180px 0 50px;
}
Let’s give a slightly different look to the span:
1
2
3
4
5
.ac-wrapper h2 span {
    display: block;
    font-size: 60%;
    color: #c0c0c0;
}
The device will have the iPhone mockup as a background image and we will set the right dimensions. This container will need to preserve the 3D transforms and we’ll add a transition to it. Later, we’ll define a “transition classes” that will contain the properties for the altered states.
1
2
3
4
5
6
7
8
9
.ac-device {
    background: url(../images/iPhone.png) no-repeat;
    width: 288px;
    height: 611px;
    margin: 0 auto;
    position: relative;
    transition: all 0.3s ease;
    transform-style: preserve-3d;
}
The screenshot will be inside of an anchor and we’ll set the dimensions here and position it to fit into the mockup:
1
2
3
4
5
6
7
8
9
10
.ac-device a {
    height: 440px;
    width: 249px;
    display: inline-block;
    margin: 85px 0 0 20px;
}
.ac-device a img {
    display: block;
}
The title for each screenshot once it’s in the mockup view will be positioned absolutely on the right side of the device:
1
2
3
4
5
6
7
8
9
10
.ac-device h3 {
    position: absolute;
    font-size: 2.5em;
    left: 100%;
    width: 100%;
    top: 60%;
    margin-left: 30px;
    font-weight: 300;
    color: #888;
}

Now, let’s style the grid. We want to display a total of eight items so a row will have four items. Let’s set a fitting width, make it absolute and center it by setting a negative left margin (half of its width) and a left value of 50%. The initial opacity is 0 and since the grid is displayed and covering the device, we’ll set the pointer events to none so that we can’t click on it when it’s invisible. We’ll also add a transition and translate it -350px on the Z axis:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.ac-grid {
    position: absolute;
    width: 620px;
    left: 50%;
    margin-left: -310px;
    height: 100%;
    z-index: 1000;
    top: 0;
    opacity: 0;
    pointer-events: none;
    transform-style: preserve-3d;
    transition: all 0.3s ease;
    transform: translateZ(-350px);
}

The anchors in the grid will be floated left and the images inside will be set to 100% width. This will come in handy later on when we apply some media queries:

1
2
3
4
5
6
7
8
9
10
11
12
13
.ac-grid a {
    width: 145px;
    display: block;
    position: relative;
    float: left;
    margin: 10px 5px;
    cursor: pointer;
}
.ac-grid a img {
    display: block;
    width: 100%;
}

The span for the description will be positioned absolutely on top of the anchor and we’ll fade it in and move it a bit on hover:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
.ac-grid a span {
    position: absolute;
    height: 100%;
    width: 100%;
    left: 0;
    top: 0;
    text-transform: uppercase;
    padding: 3em 1em 0;
    z-index: 100;
    color: #ddd;
    background: rgba(0,0,0,0.4);
    font-weight: 700;
    opacity: 0;
    transform: translateY(-5px);
    transition: all 0.2s ease;
}
.ac-grid a:hover span {
    opacity: 1;
    transform: translateY(0);
}

Next, we’ll define the “transition classes”. When we click on the device, we’ll apply a class to the wrapper which will trigger the fading in and scaling up of the grid and the moving back of the device:

1
2
3
4
5
6
7
8
9
10
.ac-wrapper.ac-gridview .ac-device {
    transform: translateZ(-350px);
    opacity: 0.6;
}
.ac-wrapper.ac-gridview .ac-grid {
    transform: translateZ(0px);
    opacity: 1;
    pointer-events: auto;
}

Once the grid is there, we also set the pointer-events to auto again.
Our layout has some absolutely positioned elements and we’ll need to take care of them on smaller screens. The idea is that we will switch the main heading to the right side first and then center everything once the screen is very small. The second media query takes care of the grid structure. Here we will set a fluid width for both, the grid and the anchors:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
@media screen and (max-width: 63.875em) {
    .ac-wrapper {
        font-size: 60%;
        width: 100%;
        padding: 0 20px;
    }
    .ac-device {
        margin: 0;
        width: 100%;
    }
    .ac-device h3 {
        width: 50%;
        left: 290px;
    }
    .ac-wrapper h2 {
        left: 308px;
        padding: 0;
        text-align: left;
        margin-left: 30px;
    }
}
@media screen and (max-width: 39.8125em) {
    .ac-grid {
        width: 90%;
        left: 5%;
        margin-left: 0;
        padding-top: 150px;
    }
    .ac-grid a {
        width: 22%;
    }
}
@media screen and (max-width: 35.6875em) {
    .ac-wrapper {
        padding: 0 20px 100px;
    }
    .ac-wrapper h2 {
        width: 100%;
        text-align: center;
        margin: 0 0 1em;
        top: 0;
        left: auto;
        position: relative;
    }
    .ac-device {
        margin: 0 auto;
        width: 288px;
    }
    .ac-device h3 {
        position: relative;
        margin: 0;
        left: auto;
        width: 100%;
        top: 100px;
        display: block;
        text-align: center;
    }
}
And that’s all the style! Let’s take a look at the JavaScript.

The JavaScript

Let’s start by caching some elements and initialize some variables:
1
2
3
4
5
6
7
8
9
10
11
12
13
var $el = $( '#ac-wrapper' ),
    // device element
    $device = $el.find( '.ac-device' ),
    // the device image wrapper
    $trigger = $device.children( 'a:first' ),
    // the screens
    $screens = $el.find( '.ac-grid > a' ),
    // the device screen image
    $screenImg = $device.find( 'img' ),
    // the device screen title
    $screenTitle = $device.find( '.ac-title' ),
    // HTML Body element
    $body = $( 'body' );   
We will bind the events to the device’s image wrapper (anchor) and to the screen elements.

1
2
3
4
5
6
7
8
9
function init() {
    // show grid
    $trigger.on( 'click', showGrid );
    // when a grid´s screen is clicked, show the respective image on the device
    $screens.on( 'click', function() {
        showScreen( $( this ) );
        return false;
    } );
}

When the device’s image is clicked, the grid is shown. For this to happen the class “ac-gridview” has to be added to the ac-wrapper element:

1
2
3
4
5
6
function showGrid() {
    $el.addClass( 'ac-gridview' );
    // clicking somewhere else on the page closes the grid view
    $body.off( 'click' ).on( 'click', function() { showScreen(); } );
    return false;
}

When a screen element is clicked we remove the “ac-gridview” class from the ac-wrapper element, and update both, image source and title on the respective elements:

1
2
3
4
5
6
7
8
function showScreen( $screen ) {
    $el.removeClass( 'ac-gridview' );
    if( $screen ) {
        // update image and title on the device
        $screenImg.attr( 'src', $screen.find( 'img' ).attr( 'src' ) );
        $screenTitle.text( $screen.find( 'span' ).text() );
    }
}

For the third demo we also want to offer the possibility to navigate through the screenshots without having to open the grid. Depending to the direction we are navigating, the next screen will either scale up / fade in (navigating to the next screen) or move up / fade in (navigating to the previous screen). The same logic applies to the current screenshot. In order for this to work, we need to add the next/previous screen’s image to the DOM right before the current screen’s image (both images being absolute). When the transition ends we remove the old one:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
function navigate( direction ) {
    // if currently animating return
    if( animating ) {
        return false;
    }
    animating = true;
     
    // update current
    if( direction === 'next' ) {
        current = current < screensCount - 1 ? ++current : 0;
    }
    else if( direction === 'prev' ) {
        current = current > 0 ? --current : screensCount - 1;
    }
     
    // next screen to show
    var $nextScreen = $screens.eq( current );
    // if css transitions support:
    if( support ) {
        // append new image to the device and set the transition and initial style
        var $nextScreenImg = $( '<img src="' + $nextScreen.find( 'img' ).attr( 'src' ) + '">' ).css( {
            transition : 'all 0.5s ease',
            opacity : 0,
            transform : direction === 'next' ? 'scale(0.9)' : 'translateY(100px)'
        } ).insertBefore( $screenImg );
        // update title
        $screenTitle.text( $nextScreen.find( 'span' ).text() );
        setTimeout( function() {
            // current image fades out / new image fades in
            $screenImg.css( {
                opacity : 0,
                transform : direction === 'next' ? 'translateY(100px)' : 'scale(0.9)'
            } ).on( transEndEventName, function() { $( this ).remove(); } );
            $nextScreenImg.css( {
                opacity : 1,
                transform : direction === 'next' ? 'scale(1)' : 'translateY(0px)'
            } ).on( transEndEventName, function() {
                $screenImg = $( this ).off( transEndEventName );
                animating = false;
            } );
        }, 25 );
    }
    else {
        // update image and title on the device
        $screenImg.attr( 'src', $nextScreen.find( 'img' ).attr( 'src' ) );
        $screenTitle.text( $nextScreen.find( 'span' ).text() );
        animating = false;
    }
}

This navigation concept was introduced by Evan You and you can check it out here, or watch the video.

And that’s all! We hope you enjoyed this tutorial and find it inspiring!

By Mary Lou (Manoela Ilic)
Source: http://tympanus.net/codrops/2013/04/01/app-showcase-with-grid-overlay/?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+tympanus+%28Codrops%29

Tutorial Let’s Build a Lightweight Blog System Part 1

Saturday, April 6, 2013

DEMO      -     DOWNLOAD


In this tutorial, we will be making a lightweight blog system with PHP and CSS3. The blog posts will be stored in a folder as files (in the markdown format). The system will not use a database and will not have an admin panel, which makes it perfect for small blogs with only one author. It will have an RSS feed and a JSON read-only API, and will feature a completely responsive design that adapts to the screen size of the device.

In this first part, we are going to write the PHP backend, and in part 2, we will code the HTML and CSS. Let’s begin!

The posts

 

Posts will be named in the following pattern: 2013-03-14_url-of-the-post.md and they will be stored in the posts/ folder. The first part is the date of the post (you can optionally include a time as well if you have more than one post for that day), followed by an underscore, and the title of the post. The underscore is used by the system to separate the title from the date. This convention also has the benefit that posts can easily be sorted by publication date. When displayed on your blog, this post will have an URL like http://example.com/2013/03/url-of-the-post

Each post will be in the markdown format (hence the extension). The only requirement is that the first line of the markdown document is formatted as a H1 heading. For example:

1# The title of the blog post
2 
3Body of the blog post.  
This will make the first line a H1 heading. If this is the first time you’ve seen markdown, the next section is for you.

What is markdown

 

Markdown is a lightweight format for writing text. It has a minimal and intuitive syntax, which is transformed into HTML. This makes it perfect for our simple blog system, as it won’t have an admin panel nor database – all the posts will be stored in a folder as files.

We can’t simply display the raw markdown directly, first we have to transform it into HTML. There are a number of libraries that can do this (in every major language), but for this tutorial I chose the PHP Markdown library, as it integrates nicely with composer.

Composer

 

Composer is a dependency manager for PHP. With it, you can declare what libraries your project depends on, and they will be downloaded automatically for you. We will use it to include two libraries in this project:

You could simply download these libraries and use them straight away, but let’s see how we can do the same with composer (note that you need to follow these steps only if you are starting from scratch; the zip accompanying the tutorial already includes all the necessary files).
First we have to declare which packages the current project depends on, in a file named composer.json:

1{
2    "require": {
3    "dflydev/markdown": "v1.0.2",
4    "suin/php-rss-writer": ">=1.0"
5    }
6}

You can obtain the specific identifiers for the libraries and their versions from the composer package repository, or by following the instructions that each library included on its github repo.
The next steps are to install composer into your project (follow these instructions), and to run the install command. This will download all the appropriate libraries and place them in the vendor/ folder. All that is left is to include the composer autoloader in your php scripts:
1require 'vendor/autoload.php';
This will let you create instances of the libraries without having to include their PHP files individually.


The configuration file

 

I am using one additional PHP library - Dispatch. This is a tiny routing framework that I’ve mentioned before. It will let us listen for requests on specific URLs and render views. Unfortunately it doesn’t have Composer support at the moment, so we have to download it separately and include it into the project.
A neat feature of this framework is that it lets you write configuration settings in an INI file, which you can access with the config() function call. There are a number of settings you need to fill in for your blog to work:

app/config.ini

01; The URL of your blog
03 
04; Blog info
05 
06blog.title = "Tutorialzine Demo Blog"
07blog.description = "This is a lightweight and responsive blogging system.."
08blog.authorbio = "Created by ..."
09 
10posts.perpage = 5
11 
12; Framework config. No need to edit.
13views.root = app/views
14views.layout = layout

These settings are used throughout the views, so when you are setting up a new blog you won’t need to edit anything else.

The PHP code

 

Here is our main PHP file:

index.php

01// This is the composer autoloader. Used by
02// the markdown parser and RSS feed builder.
03require 'vendor/autoload.php';
04 
05// Explicitly including the dispatch framework,
06// and our functions.php file
07require 'app/includes/dispatch.php';
08require 'app/includes/functions.php';
09 
10// Load the configuration file
11config('source', 'app/config.ini');
12 
13// The front page of the blog.
14// This will match the root url
15get('/index', function () {
16 
17    $page = from($_GET, 'page');
18    $page = $page ? (int)$page : 1;
19 
20    $posts = get_posts($page);
21 
22    if(empty($posts) || $page < 1){
23        // a non-existing page
24        not_found();
25    }
26 
27     render('main',array(
28        'page' => $page,
29        'posts' => $posts,
30        'has_pagination' => has_pagination($page)
31    ));
32});
33 
34// The post page
35get('/:year/:month/:name',function($year, $month, $name){
36 
37    $post = find_post($year, $month, $name);
38 
39    if(!$post){
40        not_found();
41    }
42 
43    render('post', array(
44        'title' => $post->title .' ⋅ ' . config('blog.title'),
45        'p' => $post
46    ));
47});
48 
49// The JSON API
50get('/api/json',function(){
51 
52    header('Content-type: application/json');
53 
54    // Print the 10 latest posts as JSON
55    echo generate_json(get_posts(1, 10));
56});
57 
58// Show the RSS feed
59get('/rss',function(){
60 
61    header('Content-Type: application/rss+xml');
62 
63    // Show an RSS feed with the 30 latest posts
64    echo generate_rss(get_posts(1, 30));
65});
66 
67// If we get here, it means that
68// nothing has been matched above
69 
70get('.*',function(){
71    not_found();
72});
73 
74// Serve the blog
75dispatch();

The get() function of Dispatch creates a pattern that is matched against the currently visited URL. If they match, the callback function is executed and no more patterns are matched. The last get() call sets up a pattern that matches every URL in which case we show a 404 error.
Some of the functions you see above are not part of the Dispatch framework. They are specific to the blog and are defined in the functions.php file:

  • get_post_names() uses the glob function to find all the posts and to sort them in alphabetical order (as the date is the first part of the file name, this effectively sorts them by their publishing date);
  • get_posts() takes the list of names returned by get_post_names() and parses the files. It uses the Markdown library to convert them to HTML;
  • find_post() searches for a post by month, day and name;
  • has_pagination() is a helper function that is used in the views (we will look at them in the next part);
  • not_found() is a wrapper around Dispatch’s error function but renders a view as the message;
  • generate_rss() uses the RSS Library we mentioned above, and turns an array of posts into a valid RSS feed;
  • generate_json() is only a wrapper around json_encode, but I included it for consistency with the generate_rss function.

And here is the source:

app/includes/functions.php

001use dflydev\markdown\MarkdownParser;
002use \Suin\RSSWriter\Feed;
003use \Suin\RSSWriter\Channel;
004use \Suin\RSSWriter\Item;
005 
006/* General Blog Functions */
007 
008function get_post_names(){
009 
010    static $_cache = array();
011 
012    if(empty($_cache)){
013 
014        // Get the names of all the
015        // posts (newest first):
016 
017        $_cache = array_reverse(glob('posts/*.md'));
018    }
019 
020    return $_cache;
021}
022 
023// Return an array of posts.
024// Can return a subset of the results
025function get_posts($page = 1, $perpage = 0){
026 
027    if($perpage == 0){
028        $perpage = config('posts.perpage');
029    }
030 
031    $posts = get_post_names();
032 
033    // Extract a specific page with results
034    $posts = array_slice($posts, ($page-1) * $perpage, $perpage);
035 
036    $tmp = array();
037 
038    // Create a new instance of the markdown parser
039    $md = new MarkdownParser();
040 
041    foreach($posts as $k=>$v){
042 
043        $post = new stdClass;
044 
045        // Extract the date
046        $arr = explode('_', $v);
047        $post->date = strtotime(str_replace('posts/','',$arr[0]));
048 
049        // The post URL
050        $post->url = site_url().date('Y/m', $post->date).'/'.str_replace('.md','',$arr[1]);
051 
052        // Get the contents and convert it to HTML
053        $content = $md->transformMarkdown(file_get_contents($v));
054 
055        // Extract the title and body
056        $arr = explode('</h1>', $content);
057        $post->title = str_replace('<h1>','',$arr[0]);
058        $post->body = $arr[1];
059 
060        $tmp[] = $post;
061    }
062 
063    return $tmp;
064}
065 
066// Find post by year, month and name
067function find_post($year, $month, $name){
068 
069    foreach(get_post_names() as $index => $v){
070        if( strpos($v, "$year-$month") !== false && strpos($v, $name.'.md') !== false){
071 
072            // Use the get_posts method to return
073            // a properly parsed object
074 
075            $arr = get_posts($index+1,1);
076            return $arr[0];
077        }
078    }
079 
080    return false;
081}
082 
083// Helper function to determine whether
084// to show the pagination buttons
085function has_pagination($page = 1){
086    $total = count(get_post_names());
087 
088    return array(
089        'prev'=> $page > 1,
090        'next'=> $total > $page*config('posts.perpage')
091    );
092}
093 
094// The not found error
095function not_found(){
096    error(404, render('404', null, false));
097}
098 
099// Turn an array of posts into an RSS feed
100function generate_rss($posts){
101 
102    $feed = new Feed();
103    $channel = new Channel();
104 
105    $channel
106        ->title(config('blog.title'))
107        ->description(config('blog.description'))
108        ->url(site_url())
109        ->appendTo($feed);
110 
111    foreach($posts as $p){
112 
113        $item = new Item();
114        $item
115            ->title($p->title)
116            ->description($p->body)
117            ->url($p->url)
118            ->appendTo($channel);
119    }
120 
121    echo $feed;
122}
123 
124// Turn an array of posts into a JSON
125function generate_json($posts){
126    return json_encode($posts);
127}

At the top of the file, we have a number of use statements, which import the necessary namespaces (read more about PHP’s namespaces).

The last thing we need to do, is to rewrite all requests so they hit index.php. Otherwise our fancy routes wouldn’t work. We can do this with an .htaccess file:

1RewriteEngine On
2 
3RewriteCond %{REQUEST_FILENAME} !-f
4RewriteCond %{REQUEST_FILENAME} !-d
5 
6RewriteCond $1 !^(index\.php)
7RewriteRule ^(.*)$ index.php/$1 [L]

If a file or folder does not exist, the request will be redirected to index.php.

by Martin Angelov
source: http://tutorialzine.com/2013/03/simple-php-blogging-system/
 
Support : Femin Collection | Habitat Design | Kreatifa Media
Copyright © 2013. Kreatifa Media - All Rights Reserved
Template Created by Habitat Design Published by Kreatifa Media
Proudly powered by Blogger