Salesforce Developers Blog

Visual Contacts with Visualforce & CSS3

Avatar for Quinton WallQuinton Wall
Visualforce is a fantastic container for other web libraries and frameworks such as jQuery, CSS3, and HTML5. Here is a unique way to display Contacts within Salesforce.
Visual Contacts with Visualforce & CSS3
December 20, 2011
Listen to this article
0:00 / 0:00

I’ve been working on code and content updates to our Force.com Architecture Workshop over the past few weeks. Today I was working on the Visualforce section. It’s easy to forget that Visualforce is a container for just about any web library you can think of. Too often we get stuck on the 80+ tags provided by Salesforce. But in the world of jQuery, HTML5, CSS3 etc, we can do some really cool things.

I’ll be the first to admit I am not a ‘scripting’ expert, but it doesn’t take much work to combine some style, with Salesforce data to produce something like this:

The effect is pretty cool, and amazingly simple to do. Let’s start with the controller extension. There is nothing fancy here, just grab all the Contacts for a particular Account:

1public class AccountsVisualContacts {
2
3    public Account acct {get; set;}
4    public Id acctid {get; set;}
5    public List<Contact> allContacts { get; set;}
6
7     public AccountsVisualContacts(ApexPages.StandardController stdController) {
8        this.acct = (Account)stdController.getRecord();
9         allContacts = [select id, Name, FirstName, LastName, Wiki_Link__c, Image_URL__c from Contact where Accountid = :acct.id];
10    }
11}

Now, we can add the Visualforce page. I ‘borrowed’ the CSS from the net, and added it to the top of my Visualforce page. The rest of the code is leveraging the styles defined within an apex:repeat tag. The only other trick here to include a variable to dynamically increment a counter to allow me to reference the correct CSS style. For this simple example, I am using a predefined number of styles, but there is no reason I could not use the same incrementing variable trick to dynamically set the width and height of my polaroids.

You will also notice that I am using the standard Account controller, and my custom controller as an extension. Using the standard Account controller allows me to link directly to my Visualforce page from a custom button on the Account layout. We’ll see why this is important a bit later. I also added a custom field on the Contact object, Image_URL__c to point to an image source on the internet (specifically, images from wikipedia as we can be pretty comfortable they are not going anywhere)

1<apex:page standardController="Account" extensions="AccountsVisualContacts" sidebar="false" >
2
3    <style type="text/css">
4
5    body {
6        background-color: #E9E9E9;
7        color: #333;
8        font-family:"Lucida handwriting", "Snell Roundhand", "Helvetica Neue",Arial,Helvetica,sans-serif;
9        font-size: 16px;
10    }
11
12    .amp {
13        font-family:Garamond,Baskerville,Georgia,serif !important;
14        font-style:italic;
15        font-weight:normal;
16        border: none;
17    }
18
19    a.polaroid {
20        display: block;
21        text-decoration: none;
22        color: #333;
23        padding: 10px 10px 20px 10px;
24        width: 150px;
25        border: 1px solid #BFBFBF;
26        background-color: white;
27        z-index: 2;
28        font-size: 0.7em;
29        -webkit-box-shadow: 2px 2px 4px rgba(0,0, 0, 0.3);
30        -moz-box-shadow: 2px 2px 4px rgba(0,0, 0, 0.3);
31        box-shadow: 2px 2px 4px rgba(0,0, 0, 0.3);
32        -webkit-transition: -webkit-transform 0.5s ease-in;
33    }
34    a.polaroid:hover,
35    a.polaroid:focus,
36    a.polaroid:active {
37        z-index: 999;
38        border-color: #6A6A6A;
39        -webkit-box-shadow: 2px 2px 4px rgba(0,0, 0, 0.3);
40        -moz-box-shadow: 2px 2px 4px rgba(0,0, 0, 0.3);
41        box-shadow: 2px 2px 4px rgba(0,0, 0, 0.3);
42        -webkit-transform: rotate(0deg);
43        -moz-transform: rotate(0deg);
44        transform: rotate(0deg);
45    }
46    .polaroid img {
47        margin: 0 0 15px;
48        width: 150px;
49        height: 150px;
50    }
51
52    a img {
53        border: none;
54        display: block;
55    }
56
57    .photo-album {
58        position: relative;
59        width: 80%;
60        margin: 0 auto;
61        max-width: 70em;
62        height: 450px;
63        margin-top: 5em;
64        min-width: 800px;
65        max-width: 900px;
66    }
67    .photo-album .polaroid {
68        position: absolute;
69    }
70    .photo-album h1 {
71        position: absolute;
72        z-index: 5;
73        top: 150px;
74        text-align: center;
75        width: 100%;
76        line-height: 1.9;
77    }
78    .photo-album h1 span {
79        background-color: white;
80        font-family: "Helvetica Neue",Arial,Helvetica,sans-serif;
81        padding: 0.4em 0.8em 0.3em 0.8em;
82        -webkit-box-shadow: 2px 2px 4px rgba(0,0, 0, 0.3);
83        -moz-box-shadow: 2px 2px 4px rgba(0,0, 0, 0.3);
84        box-shadow: 2px 2px 4px rgba(0,0, 0, 0.3);
85        border: 1px solid #6A6A6A;
86    }
87    .photo-album .small {
88        width: 75px;
89        padding: 6px 6px 12px 6px;
90        font-size: 0.6em;
91    }
92    .photo-album .small img {
93        width: 75px;
94        height: 75px;
95    }
96    .photo-album .medium {
97        width: 200px;
98        padding: 13px 13px 26px 13px;
99        font-size: 0.8em;
100    }
101    .photo-album .medium img {
102        width: 200px;
103        height: 200px;
104    }
105    .photo-album .large {
106        width: 300px;
107        padding: 20px 20px 30px 20px;
108        font-size: 1em;
109    }
110    .photo-album .large img {
111        width: 300px;
112        height: 300px;
113    }
114    .photo-album .img1 {
115        bottom: 10px;
116        right: 365px;
117        -webkit-transform: rotate(10deg);
118        -moz-transform: rotate(10deg);
119        transform: rotate(10deg);
120    }
121    .photo-album .img2 {
122        top: 50px;
123        right: 20px;
124        -webkit-transform: rotate(-4deg);
125        -moz-transform: rotate(-4deg);
126        transform: rotate(-4deg);
127    }
128    .photo-album .img3 {
129        left: 400px;
130        top: 0;
131        -webkit-transform: rotate(-5deg);
132        -moz-transform: rotate(-5deg);
133        transform: rotate(-5deg);
134    }
135    .photo-album .img4 {
136        top: 10px;
137        left: 495px;
138        -webkit-transform: rotate(-20deg);
139        -moz-transform: rotate(-20deg);
140        transform: rotate(-20deg);
141    }
142    .photo-album .img5 {
143        bottom: 0;
144        right: 0;
145        -webkit-transform: rotate(1deg);
146        -moz-transform: rotate(1deg);
147        transform: rotate(1deg);
148    }
149    .photo-album .img6 {
150        bottom: 10px;
151        right: 156px;
152        -webkit-transform: rotate(6deg);
153        -moz-transform: rotate(6deg);
154        transform: rotate(6deg);
155    }
156    .photo-album .img7 {
157        bottom:0;
158        left:400px;
159        -webkit-transform: rotate(-10deg);
160        -moz-transform: rotate(-10deg);
161        transform: rotate(-10deg);
162    }
163    .photo-album .img8 {
164        bottom: -20px;
165        left: 700px;
166        -webkit-transform: rotate(-8deg);
167        -moz-transform: rotate(-8deg);
168        transform: rotate(-8deg);
169    }
170    .photo-album .img9 {
171        bottom: 0;
172        left: 0;
173        -webkit-transform: rotate(-8deg);
174        -moz-transform: rotate(-8deg);
175        transform: rotate(-8deg);
176    }
177    .photo-album .img10 {
178        top: 0;
179        left: 20px;
180        -webkit-transform: rotate(8deg);
181        -moz-transform: rotate(8deg);
182        transform: rotate(8deg);
183    }
184
185    a:hover,
186    a:focus {
187        z-index: 5;
188    }
189
190    </style>
191
192    <div>
193
194        <h1><span>Contacts of {!account.name}</span></h1>
195
196        <apex:variable var="count" value="{!1}"/>
197        <apex:repeat value="{!allContacts}" var="c">
198
199        <apex:outputLink value="/{!c.id}" styleClass="medium polaroid img{!Round(count,0)}"
200         target="_blank"><img src="{!c.Image_URL__C}" alt="{!c.Name}" />{!c.Name}</apex:outputLink>
201
202        <apex:variable var="count" value="{!count + 1}"/>
203        </apex:repeat>
204
205    </div>
206
207</apex:page>

Ok, all the hard stuff is done. All that is left is to add a custom button to our Account Details, and point it to the Visualforce page:


That’s it. Load this into your Salesforce org, and you are good to go!