Sử dụng duy nhất một thẻ <div> để vẽ tranh phong cảnh

Cập nhật: Lượt xem: 1004 [ Css ]

Sử dụng duy nhất một thẻ <div> để tập làm họa sĩ vẽ tranh phong cảnh.

Sử dụng duy nhất một thẻ <div> để vẽ tranh phong cảnh

Bình thường khi xây dựng một trang web với HTML và CSS chúng ta sẽ phải sử dụng nhiều element khác nhau, mỗi element này lại có một style CSS để cùng kết hợp tạo thành trang web.

Thế nhưng như thế thì thường quá, phàm là những thứ tầm thường trần tục mỗ sẽ không làm. Cũng là nhân dịp đầu xuân năm mới, mỗ xin mạn phép họa một bức sơn đồ chỉ dùng duy nhất một thẻ <div> mà thôi

Hình khối và cách sử dụng các thuộc tính cơ bản

Để từ ý tưởng mà hình thành nên kết quả hoàn chỉnh thì cần trải qua một số nguyên lý cơ bản về việc ta sẽ vẽ thế nào và vẽ bằng cái gì, như sau.

Để bắt đầu hãy tạo một hình khối đơn giản như sau:

//HTML
<div></div>


//CSS
div {
    width: 100px;
    height: 100px;
    background: linear-gradient(#5981b6, #5981b6);
    background-position: 0px 0px;
    background-size: 100px 100px;
    background-repeat: no-repeat;
}

init

Ở đây hãy chú ý đến thuộc tính background đang được gán cho giá trị linear-gradient() với 2 tham số là 2 màu đồng nhất, do đó ta có một hình vuông với màu xanh solid như trên.

Việc tiếp theo mỗ sẽ làm đó là phủ thêm một lớp layer màu phủ lên lớp màu xanh bên trên. Bình thường ta sẽ nghĩ ngay đến việc viết thêm 1 thẻ div bên trong và fill thẻ này với màu trắng, tuy nhiên vì đề bài đặt ra chỉ dùng duy nhất 1 thẻ div nên ta sẽ làm như sau:

div {
    background: linear-gradient(#fff, #fff), linear-gradient(#5981b6, #5981b6);
    background-position: 35px 35px, 0px 0px;
    background-size: 30px 30px, 100px 100px;
}

Kết quả:

init-2

Việc này được thực hiện như sau:

  • Đầu tiên tạo layer màu trắng thứ hai bằng linear-gradient() nằm phía trước layer màu xanh
  • Tiếp theo ta có thể điều chỉnh kích thước và vị trí hiển thị của layer này bằng việc thêm một giá trị thứ 2 vào thuộc tính position và size, miễn là giá trị này có vị trí lần lượt tương ứng với 2 layer ở trên

Cú pháp rút gọn:

background:
    /*layer Position / Size*/
    linear-gradient(#fff, #fff) 35px 35px / 30px 30px,
    linear-gradient(#5981b6, #5981b6) 0px 0px / 100px 100px;

Và vì trong một bức tranh sẽ có rất nhiều đối tượng xuất hiện, nếu mỗi đối tượng là một layer thì chúng ta sẽ có rất rất nhiều layer cần xử lý, vậy nên cách làm thông minh trong trường hợp này là sử dụng cú pháp đặt tên biến trong CSS để ghi nhớ từng layer này:

div {
    --inside-square: linear-gradient(#fff, #fff) 35px 35px / 30px 30px;
    --outside-square: linear-gradient(#5981b6, #5981b6) 0px 0px / 100px 100px;
    width: 100px;
    height: 100px;
    background:
        var(--inside-square),
        var(--outside-square);
    background-repeat: no-repeat;
    margin: 0 auto;
    margin-top: 100px;
}

Hình khối phức tạp

Tiếp tục tận dụng các thuộc tính sẵn có, ta có thể tạo ra các dạng hình khối phức tạp hơn, ví dụ như đường chéo dưới đây:

div {
    width: 200px;
    height: 100px;
    background:
        linear-gradient(12deg,#9c7842 18%,transparent 19%) 100px 0px / 100px 100px;
    background-repeat: no-repeat;
    margin: 0 auto;
    margin-top: 100px;
}

init-3

Trong hàm linear-gradient lúc này tôi đưa thêm tham số 12deg tức là góc xoay của layer, với dải màu tôi đưa vào 2 màu: đó là màu nâu chiếm 18% tỉ lệ bão hòa trong layer, dải màu thứ 2 đặt trong suốt chiếm 19% tỉ lệ bão hòa. Nếu bạn thay màu trong suốt thành màu đỏ chẳng hạn, trông nó sẽ thế này:

init-4

Tỉ lệ bão hòa cũng chính là độ pha trộn hay làm mờ của màu đó hòa vào dải màu chung. Bạn có thể thay đổi tỉ lệ này để hiểu rõ hơn cách hoạt động của nó.

Và với một chút kỹ thuật nhỏ, nhân bản hình tam giác trên và đảo ngược lại góc rồi thay đổi vị trí cho chúng nằm đối xứng nhau, tôi có được hình sau mà tôi gọi là mái nhà:

div {
    width: 200px;
    height: 100px;
    background:
        linear-gradient(-12deg,#9c7842 18%,transparent 19%) 0px 0px / 100px 100px,
        linear-gradient(12deg,#9c7842 18%,transparent 19%) 100px 0px / 100px 100px;
    background-repeat: no-repeat;
    margin: 0 auto;
    margin-top: 100px;
}

roof

Tiếp tục với một vài kỹ thuật nhỏ nữa, tôi có thể vẽ được một ngôi nhà hoàn chỉnh như sau:

div {
    --roof-one: linear-gradient(15deg,#9c7842 12%,transparent 12.5%) 50px -10px / 380px 30px;
    --roof-two: linear-gradient(-15deg,#9c7842 12%,transparent 12.5%) -330px -10px / 380px 30px;
    --window-one: linear-gradient(#fff, #fff) 20px 40px / 10px 10px;
    --window-two: linear-gradient(#fff, #fff) 70px 40px / 10px 10px;
    --house-door:  linear-gradient(#635327, #635327) 40px 40px / 20px 30px;
    --house-front: linear-gradient(#cc943f,#cc943f) 0px 20px / 100px 50px;
    width: 100px;
    height: 70px;
    background: 
        var(--window-one),
        var(--window-two),
        var(--roof-one),
        var(--roof-two),
        var(--house-door),
        var(--house-front);
    background-repeat: no-repeat;
    margin: 0 auto;
    margin-top: 100px;
}

frame

Hoàn thiện sản phẩm

Đầu tiên tôi tận dụng thẻ body để vẽ ra nền trời với một số đối tượng như là mây cây cỏ sau:

Mây

body {
    --sky: #CCF2FF;
    --cloud-one-1: radial-gradient( #fff 0%, #fff 30%, #fff 40%, transparent 40%) 20vmin 20vmin / 10vmin 10vmin no-repeat;
    --cloud-one-2: radial-gradient( #fff 0%, #fff 30%, #fff 40%, transparent 40%) 23vmin 20vmin / 10vmin 10vmin no-repeat;
    --cloud-one-3: radial-gradient( #fff 0%, #fff 30%, #fff 40%, transparent 40%) 26vmin 20vmin / 10vmin 10vmin no-repeat;
    --cloud-one-4: radial-gradient( #fff 0%, #fff 30%, #fff 40%, transparent 40%) 21.5vmin 18vmin / 10vmin 10vmin no-repeat;
    --cloud-one-5: radial-gradient( #fff 0%, #fff 30%, #fff 40%, transparent 40%) 24.5vmin 18vmin / 10vmin 10vmin no-repeat;
    
    min-height: 100vh;
    background:
        var(--cloud-one-5),
        var(--cloud-one-4),
        var(--cloud-one-3),
        var(--cloud-one-2),
        var(--cloud-one-1),
        var(--sky);
        
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-end;
    margin: 0;
    padding-bottom: 10vmin;
}

cloud

Vì đây là đối tượng rất phức tạp nên tôi đã phải sử dụng đến 5 lớp layer và lần lượt thay đổi vị trí của chúng để tạo ra những nếp tròn ở viền như thế kia.

Nền cỏ

Tiếp tục tôi tạo thêm 2 lớp layer nữa để giả làm nền cỏ:

body {
    --sky: #CCF2FF;
    --cloud-one-1: radial-gradient( #fff 0%, #fff 30%, #fff 40%, transparent 40%) 20vmin 20vmin / 10vmin 10vmin no-repeat;
    --cloud-one-2: radial-gradient( #fff 0%, #fff 30%, #fff 40%, transparent 40%) 23vmin 20vmin / 10vmin 10vmin no-repeat;
    --cloud-one-3: radial-gradient( #fff 0%, #fff 30%, #fff 40%, transparent 40%) 26vmin 20vmin / 10vmin 10vmin no-repeat;
    --cloud-one-4: radial-gradient( #fff 0%, #fff 30%, #fff 40%, transparent 40%) 21.5vmin 18vmin / 10vmin 10vmin no-repeat;
    --cloud-one-5: radial-gradient( #fff 0%, #fff 30%, #fff 40%, transparent 40%) 24.5vmin 18vmin / 10vmin 10vmin no-repeat;
    
    --grass-dark: linear-gradient(rgb(107, 128, 48) 0%, rgb(107, 128, 48) 100%) 0vmin 90vh / 100% 20vmin no-repeat;
    --grass-light: linear-gradient(rgb(126, 155, 51) 0%, rgb(126, 155, 51) 100%) 0vmin 90vh / 100% 5vmin no-repeat;
    
    min-height: 100vh;
    background:
        var(--cloud-one-5),
        var(--cloud-one-4),
        var(--cloud-one-3),
        var(--cloud-one-2),
        var(--cloud-one-1),
        
        var(--grass-light), 
        var(--grass-dark),
        var(--sky);
        
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-end;
    margin: 0;
    padding-bottom: 10vmin;
}

background

Cây cối

Để vẽ được cây, tôi sử dụng thêm 8 layer nữa và kết hợp với như sau:

body {
    //...
    
    --tree-big-top-1: linear-gradient(-60deg, #5f8333 12%, transparent 12.5%) 27vmin 51vmin / 60vmin 18vmin no-repeat;
    --tree-big-top-2: linear-gradient(60deg, #5f8333 12%, transparent 12.5%) 87vmin 51vmin / 60vmin 18vmin no-repeat;

    --tree-big-middle-1: linear-gradient(-60deg, #5f8333 12%, transparent 12.5%) 7vmin 68vmin / 80vmin 8vmin no-repeat;
    --tree-big-middle-2: linear-gradient(60deg, #5f8333 12%, transparent 12.5%) 87vmin 68vmin / 80vmin 8vmin no-repeat;

    --tree-big-bottom-1: linear-gradient(-60deg, #5f8333 12%, transparent 12.5%) -13vmin 75vmin / 100vmin 10vmin no-repeat;
    --tree-big-bottom-2:linear-gradient(60deg, #5f8333 12%, transparent 12.5%) 87vmin 75vmin / 100vmin 10vmin no-repeat;
    
    min-height: 100vh;
    background:
        var(--cloud-one-5),
        var(--cloud-one-4),
        var(--cloud-one-3),
        var(--cloud-one-2),
        var(--cloud-one-1),
        
        var(--tree-big-top-1),
        var(--tree-big-top-2),
        var(--tree-big-middle-1),
        var(--tree-big-middle-2),
        var(--tree-big-bottom-1),
        var(--tree-big-bottom-2),
        var(--trunk-big-2),
        var(--trunk-big-1),
        
        var(--grass-light), 
        var(--grass-dark),
        var(--sky);
        
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-end;
    margin: 0;
    padding-bottom: 10vmin;
}

tree

Kết hợp với ngôi nhà

Về phía ngôi nhà tôi đã có sửa lại thêm trông cho nó đỡ xấu, kết hợp với 2 thuộc tính là ::after và ::before ta sẽ có thành quả như sau:

pro-css

Cuối cùng

Bài viết này cũng chỉ nhằm giới thiệu một số cách sử dụng linh hoạt và nâng cao của các thuộc tính trong CSS, còn tranh có xấu hơn so với giật tít thì là lều báo mấy đời nay vẫn thế mà.

 

Nguồn: Viblo